#include <iostream>
// returns prvalue: plain auto never deduces to a reference
template < typename T > auto foo( T& t ) { return t.value() ; }
// return lvalue: auto& always deduces to a reference
template < typename T > auto& bar( T& t ) { return t.value() ; }
// return prvalue if t.value() is an rvalue
// return lvalue if t.value is an lvalue
// decltype(auto) has decltype semantics (without having to repeat the expression).
template < typename T > decltype(auto) foobar( T& t ) { return t.value() ; }
int main()
{
struct A { int i = 0 ; int& value() { return i ; } } a;
struct B { int i = 0 ; int value() { return i ; } } b;
foo(a) = 20 ; // *** error: expression evaluates to prvalue of type int
foo(b) ; // fine: expression evaluates to prvalue of type int
bar(a) = 20 ; // fine: expression evaluates to lvalue of type int
bar(b) ; // *** error: auto& always deduces to a reference
foobar(a) = 20 ; // fine: expression evaluates to lvalue of type int
foobar(b) ; // fine: expression evaluates to prvalue of type int
}
Use auto when we want to return a prvalue, but want the type to be deduced.
Use auto& or const auto& when we want to return an lvalue, but want the type to be deduced.
Use declspec(auto) when we want decltype semantics for the deduced return type.
(This is mainly useful when we write forwarding templates.)
If the return type does not use decltype(auto), the deduction follows the rules of template argument deduction.
...
If the return type is decltype(auto), the return type is as what would be obtained if the expression used in the return statement were wrapped in decltype. http://en.cppreference.com/w/cpp/language/function