1

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;
}
prometeu
  • 679
  • 1
  • 8
  • 23
  • *It works well with std::function but I can not make it compile when using function pointers* Then why not use `std::function`? It's built for this purpose. – NathanOliver Oct 28 '19 at 13:45
  • `std::function` is usually implemented using a member which is a abstract base class with a virtual function which is overriden depening on the type of the functor being passed in. If `std::function` works why not use it? – Alan Birtles Oct 28 '19 at 13:45
  • 2
    related/dupe: https://stackoverflow.com/questions/18453145/how-is-stdfunction-implemented – NathanOliver Oct 28 '19 at 13:47
  • what do you want to "repair"? Is there anything the code is supposed to do that it does not do yet? Or do you perhaps just have to remove the lines that are not working, to make it work as expected? – 463035818_is_not_an_ai Oct 28 '19 at 13:47
  • @NathanOliver My goal is to know how std::function works or how to make it work without using it. – prometeu Oct 28 '19 at 13:54
  • @NathanOliver my question is indeed related to that question. I should mention it. Thx. – prometeu Oct 28 '19 at 14:13
  • 1
    You can do this: `std::function func = std::bind(&mult::fun, obj, std::placeholders::_1, std::placeholders::_2)` or just use `auto` too.. – Brandon Oct 28 '19 at 14:27

1 Answers1

2

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);
JHBonarius
  • 10,824
  • 3
  • 22
  • 41