我们什么时候可以省略 C++11 lambda 中的返回类型

When can we omit the return type in a C++11 lambda?

本文关键字:lambda 返回类型 C++11 什么时候 我们      更新时间:2023-10-16

我所知,在标准 C++11(不是 C++14)中,当省略 lambda 的返回类型时,其返回类型被推导出为:

  1. 返回表达式的类型,只要 lambda 只包含一个带有表达式的 return 语句,或者
  2. void在所有其他情况下。

现在考虑以下代码:

#include <iostream>
auto closure = [](int x)
{
    x++;
    return x;
};
int main()
{
    int y = closure(10);
    std::cout << y << std::endl;
}

这应该属于情况 2.,但是代码编译为C++14 auto类型推导,在 g++4.9.2、g++5 和 clang++ 中,带有 -pedantic -Wall -Wextra -std=c++11 。这是怎么回事?我解释标准是错误的吗?

您的代码在没有任何警告的情况下被接受,因为原始的 C++11 限制被视为标准中的缺陷,这允许实现修复行为。请参见CWG DR975、DR1048和N3638。

975.λ返回类型扣除的限制

[在 2013 年 4 月的会议上作为文件 N3638 的一部分移至 DR 状态。

似乎没有任何技术困难需要当前的限制,即只有当 lambda 的主体由单个返回语句组成时,才能推断出 lambda 的返回类型。特别是,如果多个 return 语句都返回相同的类型,则可以允许它们。

1048.自动演绎和λ返航型演绎。

2014年11月会议记录:

CWG同意,文件N3638中体现的变化应被视为针对C++11的DR

总之,DR975 建议修改 lambda 表达式的返回类型推导规则,以允许多个返回语句。

DR1048 标识了一个差异,其中使用占位符类型推断正常函数返回类型的规则与 DR975 中提出的规则略有不同auto。具体来说,普通函数的返回类型推导在所有情况下都会丢弃顶级 cv 限定符,而 lambda 表达式的返回类型推导将保留类类型的 cv 限定符。

N3638 解决了此问题等。

<小时 />

我怀疑除了在实现上述 DR 之前找到附带 C++11 lambda 支持的编译器版本之外,有什么方法可以恢复到原始行为。

一些

C++14 规则在 C++11 模式下可用,当编译器编写者认为同时实现这两个规则太复杂时。

这是我

在C++草案标准N3337中找到的:

如果 lambda 表达式不包含 lambda 声明符,则 lambda 声明符就像 () 一样。如果 lambda 表达式不包含尾随返回类型,则尾随返回类型表示以下类型

— 如果复合语句的形式是

{ 属性说明符-seqopt return 表达式 ; }

左值到

右值转换 (4.1)、数组到指针转换 (4.2) 和函数到指针转换 (4.3) 后返回的表达式的类型;

— 否则,void.

[ 示例:

auto x1 = [](int i){ return i; }; // OK: return type is int
auto x2 = []{ return { 1, 2 }; }; // error: the return type is void (a
                                  // braced-init-list is not an expression)

结束示例 ]

该标准似乎表明:

  • 当只有一个语句存在时,并且
  • 这是一个返回语句,并且
  • 返回的对象是一个表达式

然后从表达式中推导出返回类型。否则,返回类型为 void