Why is the arrow return type declaration, after all we have auto and decltype(auto)??

Dec 3, 2016 at 11:06pm
Hi,

In which cases do we need to use the arrow for return type specification? Why is auto and decltype(auto) not always enough?

Example:
1
2
3
4
5
6
7
8
int& fc_overload(int& i) { return i;}
double fc_overload(double& d) { return d + 3;}

template<typename T>
auto function(T& t) -> decltype(fc_overload(t))
{
   return fc_overload(t);
}


I changed the above code to work only with auto but then it does not recognize the reference to int, and then changed it to return decltype(auto) and worked perfectly just as the code above...

So when is the arrow necessary?

Regards,
Juan
Dec 4, 2016 at 1:46am
auto and decltype(auto) are placeholder types that will be deduced later, based on the type of their (unambiguous) initializers.

In C++11, If you use auto as a leading return-type you must add a explicit trailing return-type specifier. In C++11 and later, the arrow only must be used to allow return-type deduction based on names which aren't visible at the leading return type. You need it to use the name t (declared in the parameter list!) in the specification of the explicit return type.

Since C++14, return-type deduction eliminates many of the cases where the arrow must be used. You can just usually write auto (or decltype(auto)) as the leading return type, and the placeholder type auto will be deduced based on the rules of template argument deduction. If that result type can't be deduced, you'll need to specify one explicitly.

But as you've seen, there is a subtle difference between the following two forms, which explicitly specifies the return type, and the latter two, which don't:
auto function(T& t) -> decltype(fc_overload(t)) { ... }
vs.
decltype(auto) function(T& t) { ... }
vs.
auto function(T& t) { ... }.

The interesting difference is between the second two because you don't really need the name t; the first form can be rewritten as
1
2
template <typename T>
decltype(fc_overload(std::declval<T>())) function(T& t) { ... }
. It's uglier, but equivalent.

See https://isocpp.org/wiki/faq/cpp14-language#decltype-auto
Dec 4, 2016 at 1:46am
> Why is auto and decltype(auto) not always enough?

There are contexts in which return type deduction with auto and decltype(auto) is not allowed or is inadequate.

For instance:
1
2
3
4
5
6
7
8
template < typename T > struct A
{
    auto some_fun( T ) const { /* ... */ }

    virtual auto foo( T v ) const { return some_fun(v) ; } // error
    virtual decltype(auto) bar( T v ) const { return some_fun(v) ; } // error
    virtual auto foobar( T v ) const -> decltype( some_fun(v) ) { return some_fun(v) ; } // fine
};


More information: see 'Return type deduction' http://en.cppreference.com/w/cpp/language/function
Topic archived. No new replies allowed.