实际上是否有理由再使用以下语法:
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];
}
尾随返回类型语法现在看起来有点多余吗?
答案 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];
}
此外,您可能会遇到推论的返回类型冲突的问题。考虑我是否要返回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();
}
跟踪返回类型使您可以精确指定要返回的表达式的类型:
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();
}
答案 1 :(得分:7)
是,至少三个原因:
T[i]
,因此您得到了类型约束或从身体返回到您的身体的转换想得到。Justin's answer中还有第四个原因。