How can I pass a member function where a free function is expected?

后端 未结 9 1682
误落风尘
误落风尘 2020-11-22 15:10

The question is the following: consider this piece of code:

#include 


class aClass
{
public:
    void aTest(int a, int b)
    {
        prin         


        
相关标签:
9条回答
  • You can stop banging your heads now. Here is the wrapper for the member function to support existing functions taking in plain C functions as arguments. thread_local directive is the key here.

    http://cpp.sh/9jhk3

    // Example program
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    typedef int FooCooker_ (int);
    
    // Existing function
    extern "C" void cook_10_foo (FooCooker_ FooCooker) {
        cout << "Cooking 10 Foo ..." << endl;
        cout << "FooCooker:" << endl;
        FooCooker (10);
    }
    
    struct Bar_ {
        Bar_ (int Foo = 0) : Foo (Foo) {};
        int cook (int Foo) {
            cout << "This Bar got " << this->Foo << endl;
            if (this->Foo >= Foo) {
                this->Foo -= Foo;
                cout << Foo << " cooked" << endl;
                return Foo;
            } else {
                cout << "Can't cook " <<  Foo << endl;
                return 0;
            }
        }
        int Foo = 0;
    };
    
    // Each Bar_ object and a member function need to define
    // their own wrapper with a global thread_local object ptr
    // to be called as a plain C function.
    thread_local static Bar_* BarPtr = NULL;
    static int cook_in_Bar (int Foo) {
        return BarPtr->cook (Foo);
    }
    
    thread_local static Bar_* Bar2Ptr = NULL;
    static int cook_in_Bar2 (int Foo) {
        return Bar2Ptr->cook (Foo);
    }
    
    int main () {
      BarPtr = new Bar_ (20);
      cook_10_foo (cook_in_Bar);
    
      Bar2Ptr = new Bar_ (40);
      cook_10_foo (cook_in_Bar2);
    
      delete BarPtr;
      delete Bar2Ptr;
      return 0;
    }
    

    Please comment on any issues with this approach.

    Other answers fail to call existing plain C functions: http://cpp.sh/8exun

    0 讨论(0)
  • 2020-11-22 15:39

    I asked a similar question (C++ openframeworks passing void from other classes) but the answer I found was clearer so here the explanation for future records:

    it’s easier to use std::function as in:

     void draw(int grid, std::function<void()> element)
    

    and then call as:

     grid.draw(12, std::bind(&BarrettaClass::draw, a, std::placeholders::_1));
    

    or even easier:

      grid.draw(12, [&]{a.draw()});
    

    where you create a lambda that calls the object capturing it by reference

    0 讨论(0)
  • 2020-11-22 15:40

    There isn't anything wrong with using function pointers. However, pointers to non-static member functions are not like normal function pointers: member functions need to be called on an object which is passed as an implicit argument to the function. The signature of your member function above is, thus

    void (aClass::*)(int, int)
    

    rather than the type you try to use

    void (*)(int, int)
    

    One approach could consist in making the member function static in which case it doesn't require any object to be called on and you can use it with the type void (*)(int, int).

    If you need to access any non-static member of your class and you need to stick with function pointers, e.g., because the function is part of a C interface, your best option is to always pass a void* to your function taking function pointers and call your member through a forwarding function which obtains an object from the void* and then calls the member function.

    In a proper C++ interface you might want to have a look at having your function take templated argument for function objects to use arbitrary class types. If using a templated interface is undesirable you should use something like std::function<void(int, int)>: you can create a suitably callable function object for these, e.g., using std::bind().

    The type-safe approaches using a template argument for the class type or a suitable std::function<...> are preferable than using a void* interface as they remove the potential for errors due to a cast to the wrong type.

    To clarify how to use a function pointer to call a member function, here is an example:

    // the function using the function pointers:
    void somefunction(void (*fptr)(void*, int, int), void* context) {
        fptr(context, 17, 42);
    }
    
    void non_member(void*, int i0, int i1) {
        std::cout << "I don't need any context! i0=" << i0 << " i1=" << i1 << "\n";
    }
    
    struct foo {
        void member(int i0, int i1) {
            std::cout << "member function: this=" << this << " i0=" << i0 << " i1=" << i1 << "\n";
        }
    };
    
    void forwarder(void* context, int i0, int i1) {
        static_cast<foo*>(context)->member(i0, i1);
    }
    
    int main() {
        somefunction(&non_member, nullptr);
        foo object;
        somefunction(&forwarder, &object);
    }
    
    0 讨论(0)
提交回复
热议问题