Problem mit boost bind und member Funktionen mit variabler Anyahl von Argumenten



  • Hallo, ich habe folgenden Quellcode:

    #include <iostream>
    #include <cstdio>
    #include <cstdarg>
    
    #include <boost/bind.hpp>
    #include <boost/function.hpp>
    
    class printfClass {
      public:
        int printf(const char* format, ...) {
        std::va_list args;
        va_start(args, format);
        int r = std::vprintf(format, args);
        va_end(args);
        return r; 
      }
    };
    
    int main(int argc, char **argv) {
       boost::function<int (const char*)> printWrapper = boost::bind<int>(std::printf, "printWrapper: %s", _1); // geht
       printWrapper("Hello World");
    
       printfClass pr;
       boost::function<int (const char*)> printClassWrapper = boost::bind<int>(&printfClass::printf, &pr, "printClassWrapper: %s", _1); //geht nicht
       printClassWrapper("Hello World");
    }
    

    Wie den Kommentaren zu entnehmen ist, geht der erste boost bind Aufruf mit std::printf als freistehende Funktion, während der zweite bind Aufruf mit printf als member Funktion in einer Klasse gekapselt nicht geht. Was ist falsch an meinen Quellcode?

    Fehlermeldung ist (Compiler: g++ 4.5 unter Ubuntu 11.04):

    In file included from /usr/include/boost/bind.hpp:22:0,
                     from /home/rust/projects/boostBindTest/main.cpp:5:
    /usr/include/boost/bind/bind.hpp: In member function ‘R boost::_bi::list3<A1, A2, A3>::operator()(boost::_bi::type<R>, F&, A&, long int) [with R = int, F = int (printfClass::*)(const char*, ...), A = boost::_bi::list1<const char*&>, A1 = boost::_bi::value<printfClass*>, A2 = boost::_bi::value<const char*>, A3 = boost::arg<1>]’:
    /usr/include/boost/bind/bind_template.hpp:32:59:   instantiated from ‘boost::_bi::bind_t<R, F, L>::result_type boost::_bi::bind_t<R, F, L>::operator()(A1&) [with A1 = const char*, R = int, F = int (printfClass::*)(const char*, ...), L = boost::_bi::list3<boost::_bi::value<printfClass*>, boost::_bi::value<const char*>, boost::arg<1> >, boost::_bi::bind_t<R, F, L>::result_type = int]’
    /usr/include/boost/function/function_template.hpp:132:42:   instantiated from ‘static R boost::detail::function::function_obj_invoker1<FunctionObj, R, T0>::invoke(boost::detail::function::function_buffer&, T0) [with FunctionObj = boost::_bi::bind_t<int, int (printfClass::*)(const char*, ...), boost::_bi::list3<boost::_bi::value<printfClass*>, boost::_bi::value<const char*>, boost::arg<1> > >, R = int, T0 = const char*]’
    /usr/include/boost/function/function_template.hpp:913:60:   instantiated from ‘void boost::function1<R, T1>::assign_to(Functor) [with Functor = boost::_bi::bind_t<int, int (printfClass::*)(const char*, ...), boost::_bi::list3<boost::_bi::value<printfClass*>, boost::_bi::value<const char*>, boost::arg<1> > >, R = int, T0 = const char*]’
    /usr/include/boost/function/function_template.hpp:722:7:   instantiated from ‘boost::function1<R, T1>::function1(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::_bi::bind_t<int, int (printfClass::*)(const char*, ...), boost::_bi::list3<boost::_bi::value<printfClass*>, boost::_bi::value<const char*>, boost::arg<1> > >, R = int, T0 = const char*, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
    /usr/include/boost/function/function_template.hpp:1064:16:   instantiated from ‘boost::function<R(T0)>::function(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::_bi::bind_t<int, int (printfClass::*)(const char*, ...), boost::_bi::list3<boost::_bi::value<printfClass*>, boost::_bi::value<const char*>, boost::arg<1> > >, R = int, T0 = const char*, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
    /home/rust/projects/boostBindTest/main.cpp:24:130:   instantiated from here
    /usr/include/boost/bind/bind.hpp:382:98: error: no match for call to ‘(boost::_mfi::dm<int(const char*, ...), printfClass>) (printfClass*&, const char*&, const char*&)’
    /usr/include/boost/bind/mem_fn.hpp:340:9: note: candidates are: R& boost::_mfi::dm<R, T>::operator()(T*) const [with R = int(const char*, ...), T = printfClass]
    /usr/include/boost/bind/mem_fn.hpp:345:15: note:                 const R& boost::_mfi::dm<R, T>::operator()(const T*) const [with R = int(const char*, ...), T = printfClass]
    /usr/include/boost/bind/mem_fn.hpp:357:9: note:                 R& boost::_mfi::dm<R, T>::operator()(T&) const [with R = int(const char*, ...), T = printfClass]
    /usr/include/boost/bind/mem_fn.hpp:362:15: note:                 const R& boost::_mfi::dm<R, T>::operator()(const T&) const [with R = int(const char*, ...), T = printfClass]
    make[2]: *** [CMakeFiles/boostbindtest.dir/main.cpp.o] Error 1
    make[1]: *** [CMakeFiles/boostbindtest.dir/all] Error 2
    make: *** [all] Error 2
    *** Failed ***
    


  • 299792458 schrieb:

    Was ist falsch an meinen Quellcode?

    Du versuchst, oldscool C-Mittel (Ellipse und va_args) mit modernen C++-Mitteln zu verknüpfen. Was willst du damit erreichen?



  • Ich verwende JNI um von Java-Code auf eine C-Bibliothek zu zugreifen.
    JNI ist reines C mit einem ganz dünnen C++-Wrapper drumherum. Ich selber habe eine C++-Bibliothek geschrieben, die mittels xcb-xv auf XV zugreift. Für diese Bibliothek möchte ich jetzt eine Anbindung an Java schreiben. Meine Bibliothek bietet es an einen Callback zu registrieren, der falls sich ein Wert in XV verändert hat, aufgerufen wird (simples Eventhandling). Diese Funktion wird in einem boost::function Objekt gekapselt. Für meine Java-Anbindung soll statt einer normalen C++-Funktion eine Java-Funktion aufgerufen werden. Java-Funktionen werden in JNI mittels einer Helperfunktion aufgerufen, die das Javaobjekt und die methodID als feste Parameter erwartet, danach folgt eine variable Anzahl von Argumenten, die an die Java Funktion übergeben werden. Ich möchte jetzt die JNI spezifischen Sachen an die Funktion binden, damit ich eine Funktion erhalte, die ich meiner C++ Bibliothek übergeben kann.
    Das heißt aus

    env->CallVoidMethod(listener, changeNotifyListenerChangeOccurredMethodID, arg1, arg2, arg3)
    

    soll

    helperFunction(arg1, arg2, arg3)
    

    werden. Damit ich für helperFunction dann eine boost::function Objekt erzeugen kann, wie es meine C++-Bibliothek erwartet. Hier die Signatur der entsprechen Funktion aus meiner Bibliothek:

    void registerChangeNotifyFunction(boost::function<void (std::size_t adaptorIndex, std::size_t attributeIndex, int32_t value)> func);
    

    Der boost::bind Aufruf sieht so aus:

    boost::bind<void>(&JNIEnv::CallVoidMethod, env, listener, changeNotifyListenerChangeOccurredMethodID, _1, _2, _3)
    

    Das hat allerdings nicht funktioniert(ließ sich nicht kompilieren), also habe ich um festzustellen wo das Problem liegt, versucht ein minimales Programm zu schreiben, wo dasselbe Problem auftritt. Dieses minimale Code-Beispiel habe ich dann hier gepostet. D.h der in meinen ersten Post gezeigte Quellcode verdeutlicht nur mein Problem, hat damit aber sonst eigentlich nicht viel zu tun.



  • Im JNI gibt es für jede Ellipsenfunktion auch eine, die va_list enggegennimmt. zum Beispiel kann man

    va_list args;
    
    // va_start(args, yadda yadda);
    
    env->CallVoidMethodV(listener, changeNotifyListenerChangeOccurredMethodID, args);
    //                 ^-- V hier.
    
    va_end(args);
    

    schreiben.



  • seldon schrieb:

    Im JNI gibt es für jede Ellipsenfunktion auch eine, die va_list enggegennimmt. zum Beispiel kann man

    va_list args;
    
    // va_start(args, yadda yadda);
    
    env->CallVoidMethodV(listener, changeNotifyListenerChangeOccurredMethodID, args);
    //                 ^-- V hier.
    
    va_end(args);
    

    schreiben.

    Entschuldige, aber ich verstehe nicht ganz wie mir das helfen soll. Ich hätte gerne die Möglichkeit, dass meine C++-Bibliothek eine Java-Funktion als Callback aufrufen kann. Meine C++-Bibliothek beinhaltet eine Klasse XVAttributeManager mit einer Methode registerChangeNotifyFunction:

    class XVAttributeManager : boost::noncopyable {
    public:
       // you can register a function, which will be called from lookForChanges, waitForChanges or observeChanges in case the value of an attribute has changed
        void registerChangeNotifyFunction(boost::function<void (std::size_t adaptorIndex, std::size_t attributeIndex, int32_t value)> func);
    
       // Rest weg gelassen
    };
    

    Damit ich mittels dieser Methode eine Java-Funktion als Callback setzen kann, muss ich es schaffen den ganzen JNI-Krams(jobject und jmethodID) an env->CallVoidMethod() zu binden, sodass eine Funktion mit der Signatur:

    void wrappedJNICallVoidMethodFunction(std::size_t, std::size_t, int32_t)
    

    herauskommt.


Log in to reply