问题
Is there actually any reason to use the following syntax anymore :
template<typename T>
auto access(T& t, int i)
-> decltype(t[i])
{
return t[i];
}
Now that we can use :
template<typename T>
decltype(auto) access(T& t, int i)
{
return t[i];
}
The trailing return type syntax now seems a little redundant?
回答1:
Deduced return types are not SFINAE friendly. This overload will simply drop out of the overload set if t[i]
is invalid:
template<typename T>
auto access(T& t, int i)
-> decltype(t[i])
{
return t[i];
}
Whereas this overload will not, leading to a hard error:
template<typename T>
decltype(auto) access(T& t, int i)
{
return t[i];
}
Demo
Also, you can run into issues with conflicting deduced return types. Consider if I wanted to return a std::optional<T>
. The following code doesn't compile since std::nullopt_t
is not the same type as 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();
}
Trailing return types let you specify exactly which expressions' type to 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();
}
You could use a leading return type, but it would require the use of std::declval
, which makes it harder to understand:
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
回答2:
Yes, at least three reasons:
- Meaningful declaration: Your first variant has a declaration which tells me what the return type is; your second variant requires that I read your definition. But your definition might be in another file, or not very clear.
- Type constraint or type conversion: Your body could be returning something other than the expression
T[i]
, and thus you get a type constraint or a conversion from what the body returns to what you want to get. - Backwards compatibility: This may seem trivial to you, but try writing a library and telling your users "Oh, you need a C++14-conformant compiler because of my cute syntax choices".
And there's also a fourth reason in Justin's answer.
来源:https://stackoverflow.com/questions/52123331/legitimate-uses-of-the-trailing-return-type-syntax-as-of-c14