自 C++14 起,尾随 return 类型语法的合法使用
Legitimate uses of the trailing return type syntax as of C++14
是否真的有理由再使用以下语法:
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];
}
结尾的 return 类型语法现在看起来有点多余?
是的,至少三个原因:
- 有意义的声明:你的第一个变体有一个声明,它告诉我return类型是什么;你的第二个变体要求我阅读你的定义。但是你的定义可能在另一个文件中,或者不是很清楚。
- 类型约束或类型转换:你的 body 可能 returning 表达式
T[i]
以外的东西,因此你得到类型约束或从 body return 到您想要的内容的转换。
- 向后兼容性:这对您来说似乎微不足道,但请尝试编写一个库并告诉您的用户"Oh, you need a C++14-conformant compiler because of my cute syntax choices"。
Justin's answer还有第四个原因。
推导的 return 类型对 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];
}
此外,您可以 运行 解决推导的 return 类型冲突的问题。考虑一下我是否想 return 一个 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();
}
尾随 return 类型让您可以准确指定表达式的类型 return:
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();
}
您可以使用前导 return 类型,但它需要使用 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();
}
是否真的有理由再使用以下语法:
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];
}
结尾的 return 类型语法现在看起来有点多余?
是的,至少三个原因:
- 有意义的声明:你的第一个变体有一个声明,它告诉我return类型是什么;你的第二个变体要求我阅读你的定义。但是你的定义可能在另一个文件中,或者不是很清楚。
- 类型约束或类型转换:你的 body 可能 returning 表达式
T[i]
以外的东西,因此你得到类型约束或从 body return 到您想要的内容的转换。 - 向后兼容性:这对您来说似乎微不足道,但请尝试编写一个库并告诉您的用户"Oh, you need a C++14-conformant compiler because of my cute syntax choices"。
Justin's answer还有第四个原因。
推导的 return 类型对 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];
}
此外,您可以 运行 解决推导的 return 类型冲突的问题。考虑一下我是否想 return 一个 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();
}
尾随 return 类型让您可以准确指定表达式的类型 return:
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();
}
您可以使用前导 return 类型,但它需要使用 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();
}