【问题标题】:Is auto in template parameter list in lambdas part of the standard?lambdas 模板参数列表中的 auto 是标准的一部分吗?
【发布时间】:2015-11-26 03:18:28
【问题描述】:

今天无意中发现了如下代码sn-p:

#include <utility>

int main()
{

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

  };

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

http://cpp.sh/5p34

我只有一个问题:标准是否支持此代码?

它在 GCC 中编译(使用 -std=c++14),但不是 clang 或 Visual Studio 2015 (VC++14)。

这似乎应该成为标准的一部分,因为如果 lambda 应该具有与常规函数相同的模板支持,那么应该支持。

这似乎转换为所有模板类型,而不仅仅是std::pair

【问题讨论】:

  • 这称为泛型 lambda,是 C++14 的一部分
  • @v.oddou 我知道这样的功能,我只是对为什么该示例无法在 Clang AND Visual Studio 下编译感到困惑。您是在提议 Clang 和 VC++14 中都存在错误吗?
  • 有趣。我不知道在普通函数声明中允许使用auto。同样,它可以在 GCC 中编译,但不能在 clang 或 VC++14 中编译。
  • 正确,因为它是concepts lite的一部分,不在C++14中,但gcc支持它作为扩展。

标签: c++ templates c++11 lambda type-deduction


【解决方案1】:

在 C++14 中,auto 不允许在模板参数中使用,无论是否在 lambda 中。 Clang 和 Visual Studio 都有权拒绝此代码。

C++14 标准参考是 [dcl.spec.auto]。在以下情况下允许使用 auto 说明符:

  • 在函数声明符的 decl-specifier-seq 中(例如auto f();)(第 2 段)
  • conversion-function-id 中(类中的 operator auto())(第 2 段)
  • 在函数声明符的 trailing-return-type 中(例如auto f() -&gt; auto;)(第 2 段)
  • parameter-declaration(作为 decl-specifiers 之一)的 decl-specifier-seq 中(第3); -这就是允许通用 lambda 存在的原因-
  • 在块作用域或命名空间作用域的变量声明中(第 4 段)
  • 在 for 循环控制变量的声明中(第 4 段),包括基于范围的 for 循环(第 5 段)
  • ifswitch 语句或循环的条件下(第 5 段)
  • new 表达式中,即, new auto(42)(第 5 段)
  • 在类定义中声明静态数据成员(第 5 段)

最后,

在本节未明确允许的上下文中使用 autodecltype(auto) 的程序是格式错误的。

因此,auto 不允许出现在模板参数中,因为 [dcl.spec.auto] 中没有枚举这种情况。

我不知道为什么 gcc 允许它。它可能与概念精简版有关,但我不知道概念精简版是否真的允许这种用法。它可能只是一个易于实现的无关扩展。我认为

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

被翻译成

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

【讨论】:

  • 据我所知,decl-specifier-seq of a parameter-declaration in []( T&lt;auto&gt; param ) auto 存在于声明说明符序列中。
  • 是的,它来自Concepts。它允许pair&lt;auto, auto&gt; 甚至pair&lt;auto (*)(auto, auto), auto (auto::*)(auto)&gt;(TS 中的实际示例)。每个auto 都是它自己的无约束类型模板参数。
  • @v.oddou Brian 是缩写。实际的措辞是“作为参数声明的 decl-specifier-seq 中的 decl-specifiers 之一”。
【解决方案2】:

据我所知,这是concepts lite 的一部分,gcc 允许它作为 C++14 中的扩展,类似于'auto' not allowed in function prototype with Clang 中的问题,尽管与之前使用-pedantic 的情况不同,它不会产生像扩展程序一样的警告。

据我所知,与上面链接的概念 lite 提案最相关的变化是7.1.6.4 [dcl.spec.auto]8.3.5 部分[dcl.fct] ;来自7.1.6.4

修改第 3 段以允许在 lambda 或函数的参数类型中使用 auto。

  1. 如果自动类型说明符出现在 作为参数声明的 decl-specifier-seq 中的 decl-specifiers 之一 在 lambda 表达式的参数类型,该 lambda 是一个泛型 lambda (5.1.2)。 [ 例子:

    auto glambda = [](int i, auto a) { return i; }; // OK:一个通用的 lambda

end example ] 同样,如果 auto 类型说明符出现在函数声明的参数类型中,则函数声明 声明一个缩写函数模板 (8.3.5)。 [示例:

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

—结束示例]

来自8.3.5

在第 15 段之后添加以下段落。

  1. 缩写函数模板是一种函数声明,其参数类型列表包含一个或多个占位符(7.1.6.4, 7.1.6.5)。缩写函数模板等价于一个函数模板 (14.5.6),其模板参数列表包括一个发明 每次出现的占位符的模板参数 参数声明子句,按出现顺序。如果 占位符由 auto 类型说明符指定,然后 相应的发明模板参数是一个类型 模板参数。否则,占位符由 约束类型说明符和相应的发明参数 匹配原型参数 (?) 的类型和形式 由 constrainedtype- 说明符 (14.9.5) 指定的概念。这 发明的模板参数是一个参数包,如果相应的 parameter-declaration 声明函数参数包和类型 的参数只包含一个占位符。如果原型 指定概念的参数声明一个模板参数 pack,相应的参数声明应声明一个函数 参数包。缩略机的调整功能参数 函数模板派生自参数声明子句 将每次出现的占位符替换为 相应的发明模板参数。如果更换一个 带有模板参数名称的占位符会导致 参数声明无效,程序格式错误。 [ 例子:

    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))
    

[...]

【讨论】:

    猜你喜欢
    • 2012-07-05
    • 1970-01-01
    • 1970-01-01
    • 2017-04-11
    • 2011-01-20
    • 1970-01-01
    • 2019-10-28
    • 2016-09-21
    • 1970-01-01
    相关资源
    最近更新 更多