是我的书吗;s对lambda返回类型的讨论是错误的

Is my book's discussion of lambda return types wrong?

本文关键字:错误 返回类型 我的书 lambda      更新时间:2023-10-16

我的书是这样说的:

函数体包含除单个返回语句之外的任何内容的Lambdas,这些语句不指定返回类型return void。

但是这个:

auto f = []{
  int i=0; i++;
  return std::string("foo");
};
std::cout << f() << std::endl;

实际上编译并打印出"foo",但lambda-expr不仅仅有一个返回语句,因此它应该返回void,因为它没有手动指定"->std::string"作为返回类型。

这是怎么回事?

我在最新的Xcode 4.6中使用了苹果的编译器,它似乎是基于Clang 3.2的:

clang—版本

Apple LLVM 4.2版(clang-425.0.24)(基于LLVM 3.2svn)目标:x86_64-apple-darwin12.2.0线程模型:posix

本书准确地反映了本标准草案n3290中的规则。也许您的编译器实现了不同的草稿。

在第5.1.2p4节中,草案显示

如果lambda表达式不包含尾部返回类型,则为就好像尾部返回类型表示以下类型:

  • 如果复合语句的形式{属性说明符seqoptreturn表达式; }左值到右值转换、数组到指针转换和函数到指针转换后返回的表达式的类型
  • 否则无效

语法结构属性说明符seq可以是alignas或双括号属性。非变量声明。

n3485草案是在C++11发布之后提出的(即它正在朝着C++1y的方向发展),包含了相同的措辞。我不知道在n3290之前的一些草案中是否有不同的规则。

如果使用流行的编译器(gcc、Visual Studio),通常不需要指定返回类型,只要编译器能够明确地确定它即可,就像您的示例中一样。

以下示例显示了一个lambda,它需要显式的返回类型信息:

auto lambda = [](bool b) -> float
    { 
        if (b) 
            return 5.0f; 
        else 
            return 6.0; 
    };

我就此事询问了Bjarne Stroustrup,他的评论是:

I do not know if C++11 allows the deduction of the return type is there are several return statements with identical return type. If not, that's planned for C++14.

我不确定该从问题中的引号中得到什么,但以下是C++11标准对没有声明符或返回类型的lambdas的说明:

如果lambda表达式不包括lambda声明符,则为如果lambda声明符是()。如果lambda表达式没有包含尾随返回类型,就好像尾随返回类型表示以下类型(5.1.2p4):

--如果复合语句的形式为{属性说明符seqopt返回表达式;}在左值到右值转换后返回表达式(4.1),数组到指针转换(4.2)和函数到指针转换(4.3);

--否则无效。

Clang实现了对C++核心问题975的拟议解决方案。这允许lambda的任意主体,带有任意数量的返回语句,并根据返回的表达式推导返回值,条件是它们必须都产生相同的类型。

在C++14中,N3638进一步推广了这一支持,该支持在WG21的布里斯托尔会议上被投票纳入了该标准的工作草案。

Draft n3485表示,如果编译器能够明确地确定返回类型,则允许lambda不指定它。