Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a call to a template function less verbose

Tags:

c++

templates

There is a function

template <class ...T>
void foo(std::function<void(T...)> callback);

into which I pass a callback.

I'd like to do something like

foo(bar);

where bar is, for example,

void bar(int a, long b, double c, float d);

but that gives me

error: no matching function for call to bar(void (&)(int, long int, double, float))

I have to call foo as

foo(std::function<void(int, long, double, float)>(bar));

which is too verbose. Even

foo<int, long, double, float>(bar);

would have been better.

foo(bar);

would be just ideal.

Anyway, how can I make calls to foo to be less verbose?

Edit: declaration of foo has to stay the same.

like image 452
Vanilla Gorilla Avatar asked Mar 09 '15 08:03

Vanilla Gorilla


2 Answers

I'd write a wrapper function that translates the function pointer into a std::function wrapper:

template <typename... T>
void foo(std::function<void (T...)> f) {}

template <typename... T>
void foo(void (*f)(T...)) {
    foo(std::function<void (T...)>(f));
}

foo() can then be called either way:

void bar(int,double) {}

void foo_caller() {
    foo(std::function<void (int,double)>(bar));
    foo(bar);
}

Addendum: Non-static member function wrapper

Same approach can be used for pointer-to-member functions — just add another overload:

template <typename C,typename... T>
void foo(void (C::*f)(T...)) {
    foo(std::function<void (C *,T...)>(f));
}

Note the extra first parameter for the this pointer for the member function. Usage is similar:

struct quux {
    void mf(char *,double) {}
};

void foo_caller() {
    foo(&quux::mf);
}
like image 103
halfflat Avatar answered Oct 08 '22 19:10

halfflat


If you know you will pass a plain function pointer to foo, and not just any C++11 lambda, you can redefine foo as:

template <class ...T>
void foo(void(*callback)(T...)) {
   // .....
}

If you want to support lambdas, you can be more generic with the type

template <class LambdaType>
void foo(LambdaType callback) {
   // .....
}

the downside of this approach is that if you pass something that is not a function or lambda, you will get weird template error messages coming from inside of foo.


With your original solution the compiler has problems matching T... to int, long, double, float, probably because it is a nested type.

If I told you to match void(int, double) to MyTempalte<T...> you wouldn't know that I intend to replace T... with int, double, because you don't know what MyTemplate does with its arguments. Maybe MyTemplate is doing something weird to its template arguments first?

Same, the compiler doesn't know how to match std::function template parameters to your function pointer.

like image 28
CygnusX1 Avatar answered Oct 08 '22 17:10

CygnusX1