Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot call generic std::function member from template class

When compiling the following code:

#include <functional>

template <typename functionSignature>
class Class
{        
    std::function<functionSignature> func;
public:
    Class(const std::function<functionSignature>& arg) : func(arg) {}
    void callFunc() { func(); }
};

void f(const int i) {}

int main()
{
    Class<void(const int)> a(std::bind(f, 10));
    a.callFunc();
    return 0;
}

The VS 2015 compiler generates the following error message at the sixth line:

error C2064: term does not evaluate to a function taking 0 arguments.

Now, I believe this is because the compiler thinks functionSignature is not, well, a function signature; the same error happens when I instantiate and try to call operator() on an std::function<int> instead of std::function<int()>, for instance.

How can I guarantee that the template argument will always be a function signature, so that I can call operator() on the std::function?

like image 280
Stefan Dimitrov Avatar asked Feb 10 '16 19:02

Stefan Dimitrov


1 Answers

I suspect you want something like that:

template <typename F>
class Class;

template<typename R, typename... P>
class Class<R(P...)> {
public:
    std::function<R(P...)> func;
    void callFunc(P... p) { func(p...); }
};

By using partial specialization that way you can easily define the type you want.
As an example, you can use it as:

Class<int(double)> c;

Of course, I noticed that you have no constructors for your class, so to invoke func is not a good idea, but it's quite easy to define it and pass a proper function as an argument.

It follows a complete and working example where I've used the operator() to invoke the function:

#include <functional>

template <typename F>
class Class;

template<typename R, typename... P>
class Class<R(P...)> {
public:
    Class(std::function<R(P...)> f): func{f} { }
    void operator()(P... p) { func(p...); }
private:
    std::function<R(P...)> func;
};

void fn() { }

int main() {
    std::function<void()> f = fn;
    Class<void()> c{f};
    c();
}
like image 144
skypjack Avatar answered Nov 14 '22 22:11

skypjack