12

当我跳过表达式的返回类型时

C++11中的以下代码:

auto function(X x, Y y) -> decltype(x + y)
{
    return x + y;
}

等于C++14中的以下代码:

decltype(auto) function(X x, Y y)
{
    return x + y;
}

但另外可以在C++14decltype中推导出没有规则的返回类型:

auto function()
{
    return 0;
}

当我知道返回类型到底是什么时

C++11中的以下代码:

auto function() -> int
{
    return 0;
}

等于C++03中的以下代码:

int function()
{
    return 0;
}

一个不应该发生的奇怪例子

C++11中的以下代码:

auto function(X x, Y y) -> decltype(x * y)
{
    return x; // Yeah! return x with the type of x * y expression!
}

等于C++14中的以下代码:

decltype(auto) function(X x, Y y)
{
    return static_cast<decltype(x * y)>(x);
}

请纠正我,如果上面的代码是错误的并且不能按预期工作。

编辑根据评论(Yakk):它们并不真正相等,第一个(C++11示例)是隐式转换,而第二个(static_castC ++14示例)是显式转换。

结论

如您所见,我可以在不使用C++11的替代函数语法特性的情况下完成所有操作。我对么?我可以完全忘记它而不会遇到任何技术问题吗?

一般来说,可以避免以下语法:

auto function() -> TYPE
{
    return 0;
}

赞成以下语法:

TYPE function() // TYPE can be: auto, decltype(auto), or ...
{
    return 0;
}

我是否忘记了 C++11 的尾随返回类型特性的任何使用,而 C++14 的函数返回类型推导特性是不可能的?

4

1 回答 1

15

使用自动返回类型推导的函数与使用显式返回类型的函数之间存在三个重要区别(即使已计算):

  1. 如果您没有明确指定返回类型的可计算性,则无法对它进行 SFINAE:您会得到一个硬错误。为什么?因为 SFINAE 只适用于声明,而不适用于函数的定义(SFINAE: (template-argument) substitution-failure 不是错误)。

    自动返还型扣除,无 SFINAE
    SFINAE,但无自动返还型扣除

    #include <iostream>
    int doit(int x, ...) { return x; }
    template<class X, class Y> auto doit(X x, Y y)
    #ifdef TRAILING_RETURN_TYPE
    -> decltype(doit(x) + doit(y))
    #endif
    { return doit(x) + doit(y); }
    
    int main() {
        std::cout << doit(1, nullptr) << "\n";
    }
    
  2. 目前,如果定义使用自动返回类型推导,则不能用实际返回类型前向声明函数,也不能是虚拟的。(明确规则)

    7.1.6.4 自动说明符[dcl.spec.auto]

    13 具有使用占位符类型的已声明返回类型的函数或函数模板的重新声明或特化也应使用该占位符,而不是推导类型。
    14 使用占位符类型的返回类型声明的函数不应是虚拟的(10.3)。

  3. 只有具有自动返回类型推导的函数才能返回 lambda,因为没有其他方法可以获取其类型。

     auto foo() { return [] {}; }
    

该提案的链接已被纳入 C++14 草案:
http ://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3638.html

于 2014-08-16T15:06:59.390 回答