3
votes

Given the following, what type is "function"?

#include <functional>
#include <vector>

template<class T>
class Foo
{
public:

    template<typename P, typename Q, typename R, typename... Args>
    void Attach(P (Q::*f)(Args...), R p)
    {
        auto function = [p, f](Args... args)
        {
            (*p.*f)(args...);
        };

        Listeners.push_back(function);
    }   

private:

    std::vector<std::function<T>> Listeners;
};

class Bar
{
public:

    int Handler(int x, int y, int z)
    {
        return 0;
    }
};

int main(void)
{
    auto foo = Foo<int(int, int, int)>();
    auto bar = Bar();

    foo.Attach(&Bar::Handler, &bar);
}

For some context I'm attempting to make a lambda that calls a method on an instance, storing that lambda into a collection. My push_back fails to compile, with the following error:

xrefwrap(283): error C2440: 'return' : cannot convert from 'void' to 'int'

I was originally using std::bind to make a std::function that I could store. Apparently I may be able to do it with a lambda (and variadic templates, so I don't need one template per arity) but so far it's defeating me.

1
Your lambda doesn't have a return statement, but your handler returns an int. (And the function signature you use specifies int as return type.) - Mat
You're right. I changed it to return (*p.*f)(args...), then tested it with void(int,int,int) and it still works, so it's all good. - Robinson

1 Answers

6
votes

When you have constructed Foo, the explicit template argument supplied is auto foo = Foo<int(int, int, int)>();,

int main(void)
{
    auto foo = Foo<int(int, int, int)>(); //<<<< Here is the template arguments when constructing Foo 
    auto bar = Bar();

    foo.Attach(&Bar::Handler, &bar);
}

where as when you are registering the listener the function signatures return type is void

auto function = [p, f](Args... args)
    {
        (*p.*f)(args...);
    };

Resolution

So either you

  • change the explicit template argument of Foo, auto foo = Foo<void(int, int, int)>(); to return void to match your listener callback.
  • or ensure that your listener function returns an integer. return (*p.*f)(args...);

Note May be you intended to return a status code from the listener but you might have missed? So the second resolution point looks to me an obvious plausible issue