1

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.

ksl
  • 4,519
  • 11
  • 65
  • 106
  • 4
    Member functions need an object to operate on, their signature isn't compatible with `void(std::string)` in your case. You might be able to use bind to make it work, but you'll need an instance. – Mat Oct 03 '14 at 08:26
  • @Mat Please add this as an answer. – balajeerc Oct 03 '14 at 08:30
  • @Mat Please can you elaborate. – ksl Oct 03 '14 at 08:33
  • Member functions need an instance to be called on but nevertheless you can save their pointers in a vector. But since member functions have a different call signature then non-member ones saving them in the same vector will cause a problem. – a_guest Oct 03 '14 at 08:35
  • possible duplicate of [Vector of std::function with different signatures](http://stackoverflow.com/questions/26158504/vector-of-stdfunction-with-different-signatures) – Ed Heal Oct 03 '14 at 09:54
  • @EdHeal It's not a duplicate. This question relates to a specific compiler error. – ksl Oct 03 '14 at 09:56

1 Answers1

1

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

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160