Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template deduction for variadic template lambda arguments

Given the following variadic template:

template<typename... Params>
void fun(void(*f)(Params...), Params... params) {
  f(params...);
}

int main() {
  fun(+[](int a, int b) {}, 2, 3);
}

For now when invoking fun with a lambda I need to specify types of all lambda arguments explicitly. It seems redundant since the int, int could be deduced from 2, 3. Is there a way to make it more concise and automatic?

I would like the following to work, but it doesn't:

template<typename... Params>
void fun(void(*f)(Params...), Params... params) {
  f(params...);
}

int main() {
  fun(+[](auto a, auto b) {}, 2, 3);
}

I am compiling with g++ 5.4.0 and -std=c++14.

like image 357
Marcin Król Avatar asked Feb 13 '17 02:02

Marcin Król


1 Answers

Take the function by T instead of by pointer:

template<typename T, typename... Params>
void fun(T f, Params... params) {
  f(params...);
}

int main() {
  fun([](auto a, auto b) {}, 2, 3);
}

That way, the compiler can choose which overload is the right to call at the call site instead if inside the + operator. Just as said in the comment, there is no + operator defined for generic lambdas anyway.


Alternatively, you can disable the compiler from trying to deduce Params from the function pointer by using an identity alias, but I really don't recommend it. Anyway, here you go:

template<typename T>
struct identity { using type = T; };

template<typename T>
using identity_t = typename identity<T>::type;

template<typename... Params>
void fun(void(*f)(identity_t<Params>...), Params... params) {
  f(params...);
}

int main() {
  //  v----- no unary +. That operator is not defined for generic lambdas.
  fun([](auto a, auto b) {}, 2, 3);
}
like image 117
Guillaume Racicot Avatar answered Oct 26 '22 12:10

Guillaume Racicot