Search code examples
c++c++11vectorstdvectorstd-function

Compiler error when constructing a vector of std::function


Please can someone help explain why I get an error when compiling the following code using Xcode 5.1 on OS X. Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn).

#include <vector>
#include <functional>

void func1(const std::string& value)
{
    // ...
}

void func2(const std::string& value, int min, int max)
{
    // ...
}

class X
{
public:
    void x1(const std::string& value)
    {
        // ...
    }

    void x2(const std::string& value, int min, int max)
    {
        // ...
    }
};

const std::vector<std::function<void(std::string)>> functions
{
    func1,
    std::bind(func2, std::placeholders::_1, 5, 6),
    std::mem_fn(&X::x1),                                // compiler error
};

The error reported is:

no matching constructor for initialization of 'const std::vector<std::function<void (std::string)> >'
const std::vector<std::function<void(std::string)>> functions

Furthermore, I would like to add X::x2 to the vector. How would I do that?

Thanks.


Solution

  • What std::mem_fn does, it returns some unspecified object callable with an additional first argument of a pointer or reference type (or even a smart pointer type) same as the type that member function or member variable that is passed in belongs to (all other arguments are forwarded). That means you could store that object in a function wrapper like below:

    std::function<void(X*,const std::string&)> f = std::mem_fn(&X::x1);
    

    and then call it with an actual argument:

    X x{};
    f(&x, "foo"); // or std::mem_fn(&X::x1)(&x, "foo");
    

    which is same as:

    (&x)->x1("foo");
    

    In other words, this is most probably not what you wanted while storing that callable object in a std::vector of std::function<void(const std::string&)>. Instead of adding the additional first argument, you should rather bind it with a context for which that function will be invoked:

    X x{}; // object in context of which the function will be called
    
    const std::vector<std::function<void(std::string)>> functions
    {
        func1,
        std::bind(func2, std::placeholders::_1, 5, 6),
        std::bind(&X::x1, &x, std::placeholders::_1),
    //  ~~~~~~~~^ ~~~~~^  ~^            ~~~~~~~~~~^
    //     bind  function with object x and actual argument to be forwarded
    };
    

    DEMO