prometeu
prometeu

Reputation: 689

How does std::function makes pointer pointing to a member function work?

Update: Somehow related to how-is-stdfunction-implemented

The program inserts different function pointers (a multiplication from a struct, a divide as a function, and an add as lambda) into a vector and then calls the elements with the same arguments. Problems arise only from the struct.

It works well with std::function but I can not make it compile when using function pointers. Does anyone have a clue how to repair the program; or better, how does std::function works? If I use a static member function instead, the program becomes trivial (not included below).

#include <iostream>
#include <string>
#include <vector>
#include <functional>

struct mult {
    double operator()(double a, double b) { return a * b; }
    double fun(double a, double b) { return a * b; }
};

double add(double a, double b) {
    return a + b;
}

using namespace std;

int main(){

    using fnc = function<double(double, double)>;
    vector<fnc> functions;
    functions.push_back(mult{});
    functions.push_back([](double a, double b) {return a / b; });
    functions.push_back(add);

    double a = 3, b = 4;
    cout << "a=" << a << ", b=" << b << endl;
    for (int i = 0; i < 3; ++i)
        cout << functions[i](a, b) << endl;
    cout << endl;

    typedef double (*fp)(double, double);
    fp funPtr;
    vector<fp> functions1;

    //functions1.push_back(mult{}); error

    typedef double (mult::*mfp)(double, double);
    mfp f = &mult::fun;
    mult * obj = new mult;
    cout << (obj->*f)(3, 4) << endl;//          OK!
    //functions1.push_back(mfp);        ERROR!
    //functions1.push_back(obj->*f);    ERROR!
    //functions1.push_back(&mult::fun); ERROR!

    functions1.push_back([](double a, double b) {return a / b; });
    functions1.push_back(add);
    for (int i = 0; i < 2; ++i)
        cout << functions1[i](a, b) << endl;

    std::cout << "\npres enter to exit...";
    int wait_key = getchar();
    return 0;
}

Upvotes: 1

Views: 131

Answers (1)

JHBonarius
JHBonarius

Reputation: 11261

Member functions have a hidden first parameter, which is the pointer to the object it is called on. So

double mult::operator()(double a, double b) { return a * b; }

is in fact (somewhat) equal to

double operator()(mult* this, double a, double b) {
    return a * b;
}

So that's why you cannot add a mfp type object to a vector of type fp.

edit: what will work is

struct mult {
    static double fun(double a, double b) { return a * b; }
};

fp f = &mult::fun;
functions1.push_back(f);

As by making a member function static, it's no longer tied to an object.

and

functions1.push_back(mfp);

is probably a typo anyway, since mfp was the typedef, and not the function object f...

edit 2: There is also the option to use std::bind to bind the first hidden parameter to a specific object.

E.g. using your original (non-static) member function:

mult obj;
fnc temp = std::bind(&mult::fun, &obj, std::placeholders::_1, std::placeholders::_2);
functions.push_back(temp);

Upvotes: 2

Related Questions