从C++ 14开始的尾随返回类型语法的合法使用

Geo*_*ica 7 c++ trailing-return-type return-type-deduction c++14

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

template<typename T>
auto access(T& t, int i)
  -> decltype(t[i])
{
    return t[i];
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以使用:

template<typename T>
decltype(auto) access(T& t, int i)
{
    return t[i];
}
Run Code Online (Sandbox Code Playgroud)

现在,尾随返回类型语法似乎有点多余?

Jus*_*tin 17

退回的退货类型不是SFINAE友好的.如果t[i]无效,这个重载将简单地从重载集中退出:

template<typename T>
auto access(T& t, int i)
  -> decltype(t[i])
{
    return t[i];
}
Run Code Online (Sandbox Code Playgroud)

虽然这种重载不会导致硬错误:

template<typename T>
decltype(auto) access(T& t, int i)
{
    return t[i];
}
Run Code Online (Sandbox Code Playgroud)

演示


此外,您可能会遇到冲突的推断返回类型的问题.考虑我是否想要返回std::optional<T>.以下代码无法编译,因为std::nullopt_t它的类型不同std::optional<T>:

#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();
}
Run Code Online (Sandbox Code Playgroud)

使用尾随返回类型可以准确指定要返回的表达式类型:

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();
}
Run Code Online (Sandbox Code Playgroud)

你可以使用一个领先的返回类型,但它需要使用std::declval,这使得它更难理解:

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();
}
Run Code Online (Sandbox Code Playgroud)

演示


ein*_*ica 7

是的,至少有三个原因:

  1. 有意义的声明:你的第一个变体有一个声明告诉我返回类型是什么; 你的第二个版本要求我阅读你的定义.但是您的定义可能在另一个文件中,或者不是很清楚.
  2. 类型约束或类型转换:您的主体可能正在返回除表达式之外的其他内容T[i],因此您将获得类型约束或从主体返回到您想要获取的内容的转换.
  3. 向后兼容性:这对你来说似乎微不足道,但是尝试编写一个库并告诉用户"哦,你需要一个符合C++ 14标准的编译器,因为我可爱的语法选择".

贾斯汀的回答中还有第四个原因.