I'm having a little trouble using a function object create an instance of std::function. (My environment is C++ 11 using Visual Studio 2015.)

First, I have a class that is used in the argument list of my function object. Here is a simplified version that illustrates the essential point.

class X
{
public:
    void zz(int a) const
    {
        std::cout << "X:zz, a = " << a << "." << std::endl;
    }
};

Then here is the function object, which uses X in its operator() method.

class Y
{
public:
    void operator()(const X& x)
    {
        x.zz(17);
    }
};

Now, I'd like to wrap an instance of Y in a std::function. The type of the function is void(const X&), a void function taking a const reference to X as an argument. The method Y:operator() has this signature.

void test_it
{
    X my_x;

    Y my_y;
    std::function<void(const X&)> f1(my_y);
    f1(my_x); // OK

    std::function<void(const X&)> f2(Y());
    f2(my_x); // cannot convert argument 1 from X to Y

    std::function<void(const X&)> f3(Y);
    f3(my_x); // cannot convert argument 1 from X to Y

    std::function<void(const X&)> f4(Y{});
    f4(my_x); // OK
}

The first example, f1, creates an instance of Y, my_y, and creates f1 using this instance. This works fine. (The contents of Y get moved into the std::function in the std::function constructor.)

The second try, f2, constructs an instance of Y in the constructor for f2. When I try to invoke it with f2(my_x) the compiler complains that it cannot convert argument 1 (my_x) from an X to a Y.

The third try, f3, where I just name the function object class in the std::function construction of f3 fails in the same way as f2.

Finally, f4 works. In this one, I construct the function object Y using an empty initializer list.

Perhaps there is a simple explanation, but I cannot see why two of these use-cases don't compile. In particular f2, using Y(), and f4 using Y{}, seem virtually identical to me.

1 Answer 1

For the second case, the expression Y() is trying to define a function that returns a Y and that takes no arguments, and passing that function as the argument. This is known as the most vexing parse.

For the third case, you cannot give a type instead of a function argument.

The correct way to pass a default constructed instance of Y to std::function is the 4th case.

    
Thanks for the fast answer. What an appropriate name, "vexing parse". – cha 1 hour ago
    
BTW, I found while playing around after I posted, if I give the Y class a dummy int argument for its constructor, so all the Y's have to be initialized as Y(0), or Y{0}, then case 2 works using "f2(Y(0))" to construct f2 with an instance of Y as its argument. This disambiguates the situation, also. In any event, the 4th case is the easiest to use. Thanks!! – cha 1 hour ago
    
@cha If you want to use the 2nd case, you can simply wrap expression in a set of parenthesis. f2((Y())); – François Andrieux 1 hour ago