自C ++ 14起合法使用尾随返回类型语法

时间:2018-08-31 22:40:43

标签: c++ c++14 trailing-return-type return-type-deduction

实际上是否有理由再使用以下语法:

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

现在我们可以使用:

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

尾随返回类型语法现在看起来有点多余吗?

2 个答案:

答案 0 :(得分:16)

推论的返回类型不是SFINAE友好的。如果t[i]无效,则此过载将简单地退出过载设置:

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

这种过载不会导致严重错误:

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

Demo


此外,您可能会遇到推论的返回类型冲突的问题。考虑我是否要返回std::optional<T>。由于std::nullopt_tstd::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();
}

跟踪返回类型使您可以精确指定要返回的表达式的类型:

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();
}

您可以使用前导返回类型,但这将需要使用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();
}

Demo

答案 1 :(得分:7)

是,至少三个原因:

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

Justin's answer中还有第四个原因。