C++ 从C++;14

C++ 从C++;14,c++,c++14,trailing-return-type,return-type-deduction,C++,C++14,Trailing Return Type,Return Type Deduction,是否有任何理由再使用以下语法: template<typename T> auto access(T& t, int i) -> decltype(t[i]) { return t[i]; } 模板 自动访问(T&T、int i) ->decltype(t[i]) { 返回t[i]; } 现在我们可以使用: template<typename T> decltype(auto) access(T& t, int i) { re

是否有任何理由再使用以下语法:

template<typename T>
auto access(T& t, int i)
  -> decltype(t[i])
{
    return t[i];
}
模板
自动访问(T&T、int i)
->decltype(t[i])
{
返回t[i];
}
现在我们可以使用:

template<typename T>
decltype(auto) access(T& t, int i)
{
    return t[i];
}
模板
decltype(自动)访问(T&T,int i)
{
返回t[i];
}

后面的返回类型语法现在似乎有点多余了?

是的,至少有三个原因:

  • 有意义的声明:您的第一个变体有一个声明,告诉我返回类型是什么;你的第二个变体要求我阅读你的定义。但是您的定义可能在另一个文件中,或者不太清楚
  • 类型约束或类型转换:您的主体可能返回的不是表达式
    T[i]
    ,因此您会得到类型约束或主体返回的内容到您想要得到的内容的转换
  • 向后兼容性:这对您来说可能微不足道,但请尝试编写一个库并告诉您的用户“哦,由于我可爱的语法选择,您需要一个符合C++14的编译器”

  • 还有第四个原因。

    推断的回报类型不利于SFINAE。如果
    t[i]
    无效,此重载将直接从重载集中退出:

    template<typename T>
    auto access(T& t, int i)
      -> decltype(t[i])
    {
        return t[i];
    }
    
    尾部返回类型允许您精确指定要返回的表达式类型:

    template <typename T>
    auto foo(T const& val)
        -> decltype(val.some_function_returning_an_optional())
    {
        if (val.is_invalid()) return std::nullopt;
        return val.some_function_returning_an_optional();
    }
    

    也许只是我,但我有时想看看函数定义,并立即知道它会返回什么,而不只是看实现,你不是唯一的一个,C++编译器经常也喜欢这样。他们很容易与新标准特性的早期实现混淆。(或者更确切地说:编译器A在编译器B理解的代码上出错,反之亦然……)第二个示例并不好,因为您可以只执行正常的前导返回类型。我觉得只剩下sfinae表达式了。@NirFriedman这是一个简化的例子,但我遇到了一个例子,它救了我。返回类型取决于参数,但它也是可选的。可以使用前导返回类型,但一点也不好。我将改进第二个示例好吧,当我们有了概念并彻底使用它们时,返回类型推断将有一个上升趋势,因为我们让SFINAE通过了它。它可能只需要几十年的时间。@重复数据消除,或者可能取决于具体情况。对于特殊约束,
    ->decltype(t[i])
    要求的(t const&v,int i){v[i];}
    短得多。但如果某些约束使用得足够多,它们可能会转化为命名的概念,这将很好地工作。
    #include <optional> // C++17 standard library feature
    
    template <typename T>
    auto foo(T const& val)
    {
        if (val.is_invalid()) return std::nullopt;
        return val.some_function_returning_an_optional();
    }
    
    template <typename T>
    auto foo(T const& val)
        -> decltype(val.some_function_returning_an_optional())
    {
        if (val.is_invalid()) return std::nullopt;
        return val.some_function_returning_an_optional();
    }
    
    template <typename T>
    decltype(std::declval<T const&>().some_function_returning_an_optional())
    foo(T const& val)
    {
        if (val.is_invalid()) return std::nullopt;
        return val.some_function_returning_an_optional();
    }