2

I'm using C++17. I'm trying to store class member functions in a vector. I've a class where I've several functions with same signature. My scenario is to store them in a vector and execute one by one. Consider this example:

class Test
{
    int Func(const string& input, int index)
    {
        return 0;
    }

public:

    void Execute()
    {
        vector<function<int(const string&, int)>> exes;
        exes.push_back(Test::Func);
    }
};

int main()
{
    Test test;
    test.Execute();

    cout << "Hello World!" << endl;
    return 0;
}

When I try to compile it, I get the following error:

error: invalid use of non-static member function 'int Test::Func(const string&, int)'
         exes.push_back(Test::Func);
                        ~~~~~~^~~~
main.cc" data-line="13" data-column="9">main.cc:13:9: note: declared here
     int Func(const string& input, int index)

How can I achieve this in C++17?

2 Answers 2

5

Non-static class member functions aren't like freestanding functions and static member functions. They require an object to work against: the implicit this pointer; the thing to the left of the . (or ->) when calling them normally. That is, the type of &Test::Func isn't int(*)(const std::string&, int), it's int(Test::*)(const std::string&, int).

That means that Test::Func isn't compatible with std::function<int(const string&, int)>. What it is compatible with is std::function<int(Test&, const std::string&, int)> or std::function<int(Test*, const std::string&, int)>. std::function will take care of the special invocation needed to call a pointer-to-member-function for you and will do the right thing based on the type of its first parameter (either a pointer or a reference).

For example, the following will work fine:

std::function<int(Test&, const std::string&, int)> func{&Test::Func};
Test foo;
std::cout << func(foo, "hello", 42) << '\n';

If you don't want to have to supply a Test object at the call site, you can either make Func static, in which case it will behave exactly like a freestanding function, or use a lambda or std::bind to make std::function wrap a function-like object that stores a pointer or reference back to a Test instance or an entire Test instance:

Test foo;
std::function<int(const std::string&, int)> func{
    [&foo](const std::string& str, int i) {
        return foo.Func(str, i);
    }
};

// func holds a reference to foo, so no need to pass it
std::cout << func("hello", 42) << '\n';

Be careful doing this though. If you capture a reference or pointer to an object that object must still be alive when the std::function wrapper is called.

Sign up to request clarification or add additional context in comments.

Comments

1

Non-static member functions of a class always pass the this pointer implicitly as an argument. Hence the compiler error. You would have to bind the member function to an instance of a class in order to pass the this pointer.

In your case, if you have a class like:

class MyClass
{
    public:
        int Func(const std::string& input, int index)
        {
            std::cout << input << " " << index << std::endl;
            return 0;
        }
};

you can add function objects to your vector like this using std::bind or a lambda:

std::vector<std::function<int(const std::string&, int)>> exes;
MyClass obj;
//Using std::bind
exes.push_back(std::bind(&MyClass::Func, &obj, std::placeholders::_1, std::placeholders::_2));
//Or a lambda
exes.push_back([&obj](const std::string& str, int n) { return obj.Func(str, n); });

Then you can call your function objects with parameters:

for (auto &fn : exes)
{
    fn("hello", 1);
}

Demo

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.