Search code examples
c++templateslambdageneric-lambda

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.


Solution

  • 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);
    }