我们什么时候可以在 C++11 lambda 中省略 return 类型?

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

就我而言 know,在标准 C++11(不是 C++14)中,当省略 a 的 return 类型时lambda,其 return 类型推导为:

  1. returned 表达式的类型,只要 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 种情况,但是代码在 g++4.9.2、g++5 和 clang++ 中的编译就像 C++14 一样,带有 auto 类型推导,带有-pedantic -Wall -Wextra -std=c++11。这里发生了什么?我对标准的理解有误吗?

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

这是我在 C++ 草案标准 N3337 中找到的内容:

If a lambda-expression does not include a lambda-declarator, it is as if the lambda-declarator were (). If a lambda-expression does not include a trailing-return-type, it is as if the trailing-return-type denotes the following type:

— if the compound-statement is of the form

{ attribute-specifier-seqopt return expression ; }

the type of the returned expression after lvalue-to-rvalue conversion (4.1), array-to-pointer conversion (4.2), and function-to-pointer conversion (4.3);

— otherwise, void.

[ Example:

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)

end example ]

标准似乎表明:

  • 当只有一个语句存在时,并且
  • 是return语句,
  • 被return编辑的对象是一个表达式

然后从表达式推导出return类型。否则 return 类型是 void.

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

975. Restrictions on return type deduction for lambdas

[Moved to DR status at the April, 2013 meeting as part of paper N3638.]

There does not appear to be any technical difficulty that would require the current restriction that the return type of a lambda can be deduced only if the body of the lambda consists of a single return statement. In particular, multiple return statements could be permitted if they all return the same type.

1048. auto deduction and lambda return type deduction.

...

Notes from the November, 2014 meeting:

CWG agreed that the change embodied in paper N3638 should be considered to have been a DR against C++11.

综上所述,DR975 建议修改 lambda 表达式的 return 类型推导规则,以允许多个 return 语句。

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

N3638 解决了这个问题,等等。


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