6

I was able to compile the following code with gcc:

template<typename... Pack>
auto func(Pack... x) {
    return (x + ...) ;
}

template<typename... Pack>
auto lamd = [](Pack... x) {
    return (x + ...) ;
};

I can invoke the function template with func(1,2,3), but I get an error when invoking a the lambda, with lamd(1,2,3) or lamd<int>(1,2,3).

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
Nujufas
  • 676
  • 1
  • 9
  • 19

3 Answers3

5

For lambdas, you can make it generic lambda with the usage of auto.

auto lamd = [](auto... x) {
    return (x + ...) ;
};

Since C++20 you can uses an explicit template parameter list, but note that the template parameter list is still used with the operator() of the lambda, just as the usage of auto parameters. e.g.

auto lamd = []<typename... Pack>(Pack... x) {
    return (x + ...) ;
};

and then you can call it as lamd(1,2,3).

LIVE

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
3

There is no such thing as a lambda template. A lambda expression is always of a unique, new type. In particular, it is not a template that can be used for instantiating actual functions.

The function call operator that a lamdba provides, however, can be a template. And you get the syntax for free, too:

auto lamd = [](auto... x) {
    return (x + ...) ;
};

Note that C++2a will ship with additional support and explicitness for generic lambdas and allows you to

auto lambda = []<typename...T>(T&& ...args) { /* ... */ };

but this doesn't affect the issue you were facing here.

lubgr
  • 37,368
  • 3
  • 66
  • 117
3

The second definition is a variable template. It does not define the lambda's operator() as a template, but rather takes the parameter pack for the argument types of operator(). The resulting operator() is a regular member function of the instantiated variable's closure type. There is no template argument deduction possible here.

So when you write lamd<int>, the variable gets a closure type with a operator()(int), not something callable with 3 integers.

As mentioned already, you can use a generic lambda instead.

In C++20, if you'd need the lambda's argument types to be named and deduced, you can use the syntax:

auto lamd = []<typename... Pack>(Pack...) {}

This will define the operator as template, accepting a parameter pack, and leave the door open for template argument deduction.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458