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?
The trailing return type feature removes a C++ limitation where the return type of a function template cannot be generalized if the return type depends on the types of the function arguments.
Use auto and decltype to declare a function template whose return type depends on the types of its template arguments. Or, use auto and decltype to declare a function template that wraps a call to another function, and then returns the return type of the wrapped function.
In C++14, you can just use auto as a return type.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With