Search code examples
c++gccparameterslambdaclang

Parameter pack form of 'auto ... arg' is enabled in lambda but not in function?


Can someone explains me why a parameter can be declared as 'auto ... arg' in this context (when used in a lambda):

    auto glambda = [](auto a, auto&& b) { return a < b; }; 
    bool b = glambda(3, 3.14); // OK

    auto vglambda = [](auto printer) { 
        return [=](auto ... ts) { // OK: ts is a function parameter pack 
            printer(std::forward<decltype(ts)>(ts)...);
            return [=]() { printer(ts ...); };
        };
    };

    auto p = vglambda( [](auto v1, auto v2, auto v3) { std::cout << v1 << v2 << v3; } ); 

    auto q = p(1, 'a', 3.14); // OK: outputs 1a3.14 q(); // OK: outputs 1a3.14

Life example.

But not in this (when used in a function):

void func(auto ... arg)
{
}

Life example.

I would be very happy of a detailed explanation with a quotes from the latest ISO C++ draft. Or is this a bug of clang compiler? Because it compiles fine actually under gcc 5.0.


Solution

  • I found the answer by myself. It's stated in 'n4296' at § 5.1.2.5:

    The closure type for a non-generic lambda-expression has a public inline function call operator (13.5.4) whose parameters and return type are described by the lambda-expression’s parameter-declaration-clause and trailing-return-type respectively. For a generic lambda, the closure type has a public inline function call operator member template (14.5.2) whose template-parameter-list consists of one invented type template parameter for each occurrence of auto in the lambda’s parameter-declaration-clause, in order of appearance. The invented type template-parameter is a parameter pack if the corresponding parameter-declaration declares a function parameter pack (8.3.5). The return type and function parameters of the function call operator template are derived from the lambda-expression’s trailing-return-type and parameter-declarationclause by replacing each occurrence of auto in the decl-specifiers of the parameter-declaration-clause with the name of the corresponding invented template-parameter.

    This means that something like this:

    [](auto ... arg) {}
    

    Is roughly equivalent to:

    template<class ... tmp>
    ClosureType::operator()(tmp ... arg);
    

    However I don't know why isn't this also allowed in normal functions. Perhaps someone should propose it.