mercredi 27 décembre 2017

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?

Aucun commentaire:

Enregistrer un commentaire