【问题标题】:Why was the addition of trailing-return-types necessary in C++11?为什么在 C++11 中需要添加尾随返回类型?
【发布时间】:2013-05-15 02:45:51
【问题描述】:

我终于开始阅读,但我不明白为什么需要尾随返回类型。

我遇到了下面这个例子,用来突出问题:

template<class Lhs, class Rhs>
  decltype(lhs+rhs) adding_func(const Lhs &lhs, const Rhs &rhs) {return lhs + rhs;} 

这个例子是非法的,因为decltype(lhs+rhs)不起作用,因为标识符lhsrhs只有在解析阶段之后才有效。

我想我的问题是关于decltype 类型解析的时机。如果我没记错的话,关键字decltype 用于在编译时确定表达式的类型。

我没有看到在所有解析完成后让decltype 执行类型解析的缺点(这对于上面的示例来说可以正常工作)。我相信这将是解决问题的一种更简单的方法......

相反,C++11 标准提供了尾随返回类型:

template<class Lhs, class Rhs>
  auto adding_func(const Lhs &lhs, const Rhs &rhs) -> decltype(lhs+rhs) {return lhs + rhs;}

我毫不怀疑我错过了一些东西,因为我看不到尾随返回类型的其他用途。我的推理缺陷在哪里?

尾随返回类型对我来说似乎是一个过于复杂的解决方案,因为在解析完整的函数体之后具有decltype 类型解析也能正常工作?

【问题讨论】:

    标签: c++11 c++ c++11 compilation trailing-return-type


    【解决方案1】:

    我没有看到在所有解析完成后让 decltype 执行类型解析的缺点(这对于上面的示例来说可以正常工作)。

    缺点是,如果不从根本上改变 C++ 解析和处理模型的基本基础,这是不可能的。

    为了执行您的建议,编译器必须查看decltype 语法并对语法内容进行一些基本的词法分析。然后,它继续解析更多的源文件。在稍后的某个时间点(什么时候?),它决定说,“嘿,我以前看过的那些东西?我现在要为它们做所有的解析工作。”

    作为一般规则,C++ 不支持提前 来定义符号。 C++解析框架的基本假设是,如果符号在使用前没有声明,就是编译器错误。

    类可以避免使用前瞻,但仅限于其成员。这部分是因为它非常清楚何时 id 表达式可以引用成员变量(即:如果它没有引用范围内已经声明的局部或全局变量)。这不是这里的情况,我们不确定 id-expression 到底指的是什么。

    此外,您的建议会产生歧义。这是什么意思:

    int lhs;
    
    template<class Lhs, class Rhs>
      decltype(lhs+rhs) adding_func(const Lhs &lhs, const Rhs &rhs);
    

    decltype 语法是指全局lhs 变量还是局部lhs 函数参数?

    我们现在的做法,这两者之间有一个明确的界限:

    int lhs;
    float rhs;
    
    template<class Lhs, class Rhs>
      decltype(lhs+rhs) adding_func1(const Lhs &lhs, const Rhs &rhs);
    template<class Lhs, class Rhs>
      auto adding_func2(const Lhs &lhs, const Rhs &rhs) -> decltype(lhs+rhs);
    

    adding_func1 指的是全局变量。 adding_func2指的是函数参数。

    因此,您可以彻底破坏地球上所有的 C++ 编译器。或者您可以简单地后期指定您的返回类型。

    或者您可以采用 C++14 方法和not bother to state it at all

    【讨论】:

    • 感谢您的出色回答,我现在看到了用途。我希望我可以为 C++14 参考提供额外的 cookie!
    • 关于 C++14 的事情:它是否最终会被包含在内?就文档而言,这听起来像是一个充满伤害的世界……
    • @MFH:在C++14 Community Draft。所以冒着不可预见的后果,它可能会出现在 C++14 中。是的,文档可能会有些痛苦。但是话又说回来,这意味着您没有像使用decltype 来推断与函数中的代码完全对应的类型那样的无意义的冗余。
    • @NicolBolas:对于具有“decltype 返回类型”的函数,这可能不是那么糟糕,因为那些(至少从我遇到的情况来看)是模板,因此已经完全可用。另一方面,对于正常功能,这似乎是一罐蠕虫。
    • @MarcClaesen: decltype 不仅仅适用于后期指定的返回类型。
    【解决方案2】:

    一个明显的问题是它会让你陷入循环。

    typedef decltype(lhs+lhs) foo;
    foo lhs;
    

    【讨论】:

    • 是的,我知道这会有什么问题。但这些事情对我来说似乎是明显的编程错误,可以通过编译时错误来解决。
    • @MarcClaesen:但这不是一个“明确”的错误。为了检测这种类型的错误,编译器必须解决停机问题,这是不可能的。
    • 天哪,真不敢相信我错过了。谢谢@MikeSeymour!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2016-09-26
    • 2019-02-05
    • 2020-05-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多