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

时光毁灭记忆、已成空白 提交于 2020-02-27 23:06:45

问题


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.


回答1:


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 { /* ... */ }
    // ...
};



回答2:


As far as I can tell this is part of concepts lite and gcc is allowing this as an extension in C++14 similar to the issue in 'auto' not allowed in function prototype with Clang although unlike the previous case using -pedantic does not produce a warning like it should for extensions.

As far as I can tell the most relevant changes from the concepts lite proposal linked above that allow this are to section 7.1.6.4 [dcl.spec.auto] and 8.3.5 [dcl.fct] ; from 7.1.6.4:

Modify paragraph 3 to allow the use of auto within the parameter type of a lambda or function.

  1. If the auto type-specifier appears as one of the decl-specifiers in the decl-specifier-seq of a parameter-declaration in a parameter type of a lambda-expression, the lambda is a generic lambda (5.1.2). [ Example:

    auto glambda = [](int i, auto a) { return i; }; // OK: a generic lambda

end example ] Similarly, if the auto type-specifier appears in a parameter type of a function declaration, the function declaration declares an abbreviated function template (8.3.5). [ Example:

void f(const auto&, int); // OK: an abbreviated function template

— end example ]

and from 8.3.5:

Add the following paragraphs after paragraph 15.

  1. An abbreviated function template is a function declaration whose parameter-type-list includes one or more placeholders (7.1.6.4, 7.1.6.5). An abbreviated function template is equivalent to a function template (14.5.6) whose template-parameter-list includes one invented templateparameter for each occurrence of a placeholder in the parameter-declaration-clause, in order of appearance. If the placeholder is designated by the auto type-specifier, then the corresponding invented template parameter is a type template-parameter. Otherwise, the placeholder is designated by a constrained-type-specifier, and the corresponding invented parameter matches the type and form of the prototype parameter (?) of the concept designated by the constrainedtype- specifier (14.9.5). The invented template-parameter is a parameter pack if the corresponding parameter-declaration declares a function parameter pack and the type of the parameter contains only one placeholder. If the prototype parameter of the designated concept declares a template parameter pack, the corresponding parameter-declaration shall declare a function parameter pack. The adjusted function parameters of an abbreviated function template are derived from the parameter-declaration-clause by replacing each occurrence of a placeholder with the name of the corresponding invented template-parameter. If the replacement of a placeholder with the name of a template parameter results in an invalid parameter declaration, the program is ill-formed. [ Example:

    template<typename T> class Vec { };
    template<typename T, typename U> class Pair { };
    
    void f1(const auto&, auto);
    void f2(Vec<auto*>...);
    void f3(auto (auto::*)(auto));
    
    template<typename T, typename U>
    void f1(const T&, U); // redeclaration of f1(const auto&, auto)
    template<typename... T>
    void f2(Vec<T*>...); // redeclaration of f2(Vec<auto*>...)
    template<typename T, typename U, typename V>
    void f3(T (U::*)(V)); // redeclaration of f3(auto (auto::*)(auto))
    

[...]



来源:https://stackoverflow.com/questions/32322255/is-auto-in-template-parameter-list-in-lambdas-part-of-the-standard

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!