Reputation: 1261
According to [dcl.fct]/2 the snippet below is legal. GCC and clang compile and execute the code,
#include <iostream>
int i = -1;
auto f()->auto&& { return i; }
int main(){
f() = 2;
std::cout << i << '\n';
}
printing
2
But what is the purpose of allowing this in C++?
In the example above, one could get the same result just by replacing the trailing-return-type with int&
. In other words, I'm looking for an example where the trailing-return-type containing a placeholder type would be meaningful.
Upvotes: 6
Views: 292
Reputation: 85371
You can find the answer in the revision N3582 (2013-03-15)1 to the original proposal for auto
:
auto
in trailing-return-typeThis proposal initially did not allow auto in a trailing-return-type, but since then it was pointed out that putting it there is the only way to specify that a lambda returns by a deduced reference type:
[]()->auto& { return f(); }
(Remember that not only functions but also lambdas can have a trailing-return-type)
Hence [dcl.spec.auto]/2:
The
auto
type-specifier may appear with a function declarator with a trailing-return-type ([dcl.fct]) in any context where such a declarator is valid.
1 Note: N3582 has been superseded by N3638 before it was actually adopted.
Upvotes: 3
Reputation: 303127
You can make an argument about consistency: you can stick other types as trailing return types, why not placeholders?
auto f() -> int& { return i; }
auto f() -> auto& { return i; }
You can make an argument about utility: the return type for lambdas looks like a trailing return type and has no other place to put a placeholder type, so you have to allow it for lambdas anyway, so might as well allow it for functions?
auto f = []() -> int& { return i; };
auto f = []() -> auto& { return i; };
You can make an argument about code formatting. The trailing return type allows for consistent way to declare functions that always works for all cases, so just lining it up:
auto g(auto x) -> decltype(f(x)) { ... } // using trailing for parameter
auto Cls::member() -> type { ... } // using trailing for scope (to find Cls::type)
auto h(auto x) -> auto& { ... } // using trailing for formatting
There might be other arguments. But in short, it's easy to allow and clearly has merit.
Upvotes: 6