Legitimate uses of the trailing return type syntax as of C++14

  • A+
Category:Languages

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?

 


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

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: