cheater
cheater

Reputation: 53

How can I make a C++ member function by binding the arguments of another member function?

I am having problems with creating a variable of pointer-to-member-function (PTMF) type "on the fly" (that is, by pinning some arguments of an existing member function via std::bind). My question is if it is ever possible with C++11 or post-C++11 standard.

Preambula: I have a class that stores a static const array of std::functions initialized from PTMFs, hereinafter referred to as "handlers". Originally, they were regular member functions with a name and implementation so I didn't ever use C++11 and std::function. Then, I decided that many of them are nearly similar, and decided to generate them with a "generator function". I would like to avoid using templates for the generation because the number of these nearly similar handlers is going to dramatically increase in future (around 200+) and templatizing will just lead to code bloat.

If the PTMFs in question were static, I would have no problems with generating the handlers via std::bind. A simplified example:

#include <iostream>
#include <functional>


using namespace std;


struct A {
    typedef function<void(int)> HandlerFn;

    static void parametrized_handler(int i, const char *param) {
        cout << "parametrized handler: " << param << endl;
    }

    static void handler(int i) { cout << "handler 1" << endl; }

    int mm;
};

static const A::HandlerFn handler2 = [](int) { cout << "handler 2" << endl; };

static const A::HandlerFn handler3 = bind(A::parametrized_handler,
                                          placeholders::_1,
                                          "test_param");


int main()
{
    A::handler(42);
    handler2(42);
    handler3(42);

    return 0;
}

Output:

$ ./a.out 
handler 1
handler 2
parametrized handler: test_param

The problem arises when I turn to non-static member functions. std::bind is not able to generate a function object that acts like a PTMF. I know that I can pass a real object as a first argument to bind and get a working function but that is not what I want: when I am initializing a static const array, there are no objects at all, and the result of bind will act as a regular non-member function anyway.

An expected implementation for non-static member functions (with an imaginary std::bind_mem binder):

#include <iostream>
#include <functional>


using namespace std;

struct A;


struct A {
    typedef function<void(int)> HandlerFn;

    void parametrized_handler(int i, const char *param) {
        mm;
        cout << "parametrized handler: " << param << endl;
    }

    void handler(int i) const { mm; cout << "handler 1" << endl; }

    const HandlerFn handler2 = [this](int i) { mm; cout << "handler 2" << endl; };

    int mm;
};


// An imaginary PTMF binder
// static const A::HandlerFn handler3 = bind_mem(A::parametrized_handler,
//                                               placeholders::_1,
//                                               "test_param");



int main()
{
    A a;

    (a.handler)(42);
    (a.handler2)(42);
    //(a.handler3)(42);

    return 0;
}

Output:

$ ./a.out 
handler 1
handler 2

So is there a way to implement a PTMF argument binding?

Upvotes: 2

Views: 1693

Answers (1)

balki
balki

Reputation: 27674

For binding a pointer to non static member function, you need an object.

#include<functional>

struct A {
    typedef std::function<void(int)> HandlerFn;
    void mem(int);
    void static static_mem(int);
};

void foo() {
    A a;
    A::HandlerFn h1 = A::static_mem;
    //This captures a by ref
    A::HandlerFn h2 = std::bind(&A::mem, std::ref(a), std::placeholders::_1);
    //This captures a by copy
    A::HandlerFn h3 = std::bind(&A::mem, a, std::placeholders::_1);
    //Change to =a for copy
    A::HandlerFn h4 = [&a](int i){
        a.mem(i);
    };
    h1(34);
    h2(42);    
}

Link:https://godbolt.org/g/Mddexq

Upvotes: 2

Related Questions