Search code examples
c++templatesc++11lambdatype-deduction

Is auto in template parameter list in lambdas part of the standard?


Today, I stumbled across the following code snippet:

#include <utility>

int main()
{

  auto a = [](std::pair<auto, auto> value)
  {

  };

  a(std::pair<int, bool>{ 3, true });
}

http://cpp.sh/5p34

I have only one question: is this code supported by the standard?

It compiles in GCC (with -std=c++14), but not clang or Visual Studio 2015 (VC++14).

This seems like it should be part of the standard because if lambdas should have the same template support as regular functions, then this should be supported.

This seems to convert to all template types, not just std::pair.


Solution

  • In C++14, auto is not allowed in template arguments, whether in a lambda or not. Clang and Visual Studio are both right to reject this code.

    The C++14 standard reference is [dcl.spec.auto]. The auto specifier is allowed in the following contexts:

    • In the decl-specifier-seq of a function declarator (e.g., auto f();) (paragraph 2)
    • In a conversion-function-id (i.e., an operator auto() in a class) (paragraph 2)
    • In the trailing-return-type of a function declarator (e.g., auto f() -> auto;) (paragraph 2)
    • In the decl-specifier-seq of a parameter-declaration (as one of the decl-specifiers) of a lambda (paragraph 3); -this is what allows generic lambdas to exist-
    • In the declaration of a variable at block scope or namespace scope (paragraph 4)
    • In the declaration of a for loop control variable (paragraph 4), including a range-based for loop (paragraph 5)
    • In the condition of an if or switch statement or a loop (paragraph 5)
    • In a new expression, i.e., new auto(42) (paragraph 5)
    • In the declaration of a static data member in the definition of a class (paragraph 5)

    Finally,

    A program that uses auto or decltype(auto) in a context not explicitly allowed in this section is ill-formed.

    Therefore, auto is not allowed in template parameters, since that case isn't enumerated in [dcl.spec.auto].

    I don't know why gcc allows it. It might be related to Concepts Lite, but I don't know if Concepts Lite actually allows this usage. It could just be an unrelated extension that is easy to implement. I assume that

    [](std::pair<auto, auto> value) { /* ... */ }
    

    is translated into

    struct __some_unique_name {
        template <typename T1, typename T2>
        auto operator()(std::pair<T1, T2> value) const { /* ... */ }
        // ...
    };