Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using std::function as a delegate in C++11

Say I have these 3 different functions that I may want to point to:

float test1(int a, int b) {
    return 7.0f;
}

struct TestClass {
    float test2(int a, int b) {
        return 5.0f;
    }
};

struct TestClass2 {
    float  test3(int a, int b) {
        return 3.0f;
    }
};

Notice how all three use the same arguments and return value. I want to abstract away whether or not it is a member function and which class it belonged to. I want a delegate type that could be referring to any of these 3 functions depending only on how it was initialized.

Here is my first attempt:

typedef std::function<float(int, int)> MyDelegate; // is this right?

int main() {
    TestClass obj; 
    TestClass2 obj2;

    MyDelegate a = test1;
    MyDelegate b = std::bind(std::mem_fn(&TestClass::test2), obj); // is this right?
    MyDelegate c = std::bind(std::mem_fn(&TestClass2::test3), obj2); // is this right?

    return 0;
}

The idea is I want to also store the 'this' pointer inside the wrapper too. This way, it's like a fully functional delegate.For example, invoking 'b(x, y)' should be like calling obj.test2(x, y).

I just can't even make it compile, I'm probably not fully grasping this. I'm kind of new to these libraries and the errors in VS2012 are catastrophically unhelpful. Any help would be appreciated.

like image 212
VoidStar Avatar asked Sep 13 '12 10:09

VoidStar


3 Answers

You need to tell std::bind what to do with the other function parameters. In order to make the call b(x, y) delegate x and y to the two original function parameters you need to use placeholders from the std::placeholders namespace:

std::bind(&TestClass::test2, obj, std::placeholders::_1, std::placeholders::_2);

And there's also no need for std::mem_fn (it works, though), since std::bind already handles member functions correctly (making the implicit this argument an explicit first argument, like std::mem_fn does).

like image 93
Christian Rau Avatar answered Oct 23 '22 08:10

Christian Rau


You need to provide 2 arguments to std::bind or provide placeholders to provide them later:

std::function<float(int, int)> c = std::bind(&TestClass2::test3, obj2, 1, 2);
c(); //returns result

OR

std::function<float(int, int)> c = std::bind(&TestClass2::test3, obj2, std::placeholders::_1, std::placeholders::_2);
c(1, 2); //returns result

More information about std::bind is here.

like image 43
Denis Ermolin Avatar answered Oct 23 '22 10:10

Denis Ermolin


Using visual C++ compiler (CTP 2012) i spied how they did std::function and deliviered my own solution to handle member functions

usage looks like: http://ideone.com/v5zfDn

class Window
{
public:
    void Show( int number ) const
    {
        //...
    }

    void ShowDynamic( int number ) volatile
    {
        //...
    }
};

void ShowWindows( int param )
{
    //...
}

int main()
{
    Window window;

    typedef mezutils::Delegate< void( int ) > Notifier;
    Notifier notifier;

    notifier = &ShowWindows;
    notifier( 0 );

    notifier = Notifier( &window, &Window::Show );
    notifier( 1 );

    notifier = [](int x) { /*...*/ };
    notifier( 2 );

    void (*funpc)(int) = func;
    notifier = funpc;
    notifier( 3 );

    notifier = [](int arg) { printf("asd %d\r\n",arg); };
    notifier(4);
    return 0;
}

delegate class looks like: http://ideone.com/DebQgR

of course it is a prototype made for fun, but i like it because it's clear

like image 2
mezdejek namejek Avatar answered Oct 23 '22 10:10

mezdejek namejek