【问题标题】:When can we omit the return type in a C++11 lambda?我们什么时候可以省略 C++11 lambda 中的返回类型?
【发布时间】:2015-05-11 09:42:26
【问题描述】:

据我know,在标准 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。但是,在 g++4.9.2、g++5 和 clang++ 中,代码编译就像是带有 auto 类型推导的 C++14,带有 -pedantic -Wall -Wextra -std=c++11。这里发生了什么?我是不是对标准的解释错了?

【问题讨论】:

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


    【解决方案1】:

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

    975。 lambda 的返回类型扣除限制

    [作为论文 N3638 的一部分,在 2013 年 4 月的会议上转为 DR 状态。]

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

    1048。自动推演和lambda返回类型推演。

    ...

    2014 年 11 月会议记录:

    CWG 同意论文 N3638 中体现的更改应被视为针对 C++11 的 DR。

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

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

    N3638 解决了这个问题。


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

    【讨论】:

    • 我还是有点迷茫。 lambda 的主体是否可以包含多个语句但只有一个 return 语句,或者它的整个主体必须​​只包含一个 return 语句才能应用我的案例 1.?
    • 实际上,该提议的决议没有被采纳。相反,N3638 是,然后DR1048 澄清说 N3638 对 lambdas 的更改应被视为针对 C++11 的 DR。
    • @T.C.在我链接到 :S 的 DR 正下方,应该继续阅读。谢谢。
    • @vsoftco 我删除了我在第一次编辑中添加的文本,因为引用 DR 的答案变得不必要地冗长,但绝对允许多个 return 语句,而不仅仅是多个语句最终导致一个 return声明。
    【解决方案2】:

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

    【讨论】:

    • 所以,理论上,我的代码不是 100% C++11 兼容的,对吧?
    • 是的,在 C++11 中似乎不会被接受。
    • 我认为您可以使用逗号运算符使其成为单个语句,然后它将与 C++11 兼容
    • @LưuVĩnhPhúc 问题是我有一些代码,其中 lambda 具有明显更多的语句,并且我的代码编译得很好(在最大警告级别没有警告 + 迂腐)而没有明确指定返回类型。
    【解决方案3】:

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

    如果 lambda-expression 不包含 lambda-declarator,则如同 lambda-declarator 是 ()。如果 lambda-expression 不包含 trailing-return-type,则好像 trailing-return-type 表示以下类型:

    ——如果复合语句的形式是

    { attribute-specifier-seqoptreturn expression ; }

    左值到右值转换(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。

    【讨论】:

    • 是的,所以看起来 lambda 的主体应该只包含 return something;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-31
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 2021-02-05
    • 1970-01-01
    相关资源
    最近更新 更多