Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 429
George Avatar asked Aug 31 '18 22:08

George


People also ask

Why use trailing return type c++?

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.

What does Decltype auto do?

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.

Can return type be auto?

In C++14, you can just use auto as a return type.


1 Answers

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

like image 177
Justin Avatar answered Oct 07 '22 06:10

Justin