The proposals for C++14 include one (N3638, by Jason Merrill) that defines a special declaration to accomplish this, using decltype(auto)
instead of auto
:
template <class A>
struct C{
decltype(auto) func()
{
return a.func();
}
A a;
};
GCC implements this in the 4.9 snapshot, see the C++ section.
When changing the final parts of your code to
static_assert(std::is_same<decltype(c1.func()), int>::value, "true");
static_assert(std::is_same<decltype(c2.func()), int&>::value, "true");
static_assert(std::is_same<decltype(c3.func()), const int&>::value, "true");
static_assert(std::is_same<decltype(c4.func()), int&&>::value, "true");
the GCC 4.9 snapshot compiles it, while 4.8 does not.
(Note: Both compilers will crash on an internal compiler error if you use the -g
option when compiling. This is due to Bug 56014.)
For the sake of completeness, here is the most relevant section from the proposal:
If the placeholder is the decltype(auto) type-specifier, the declared type of the variable or return type of the function shall be the placeholder alone. The type deduced for the variable or return type is determined as described in 7.1.6.2, as though the initializer had been the operand of the decltype. [ Example:
int i; int&& f(); auto x3a = i; // decltype(x3a) is int decltype(auto) x3d = i; // decltype(x3d) is int auto x4a = (i); // decltype(x4a) is int decltype(auto) x4d = (i); // decltype(x4d) is int& auto x5a = f(); // decltype(x5a) is int decltype(auto) x5d = f(); // decltype(x5d) is int&& auto x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int> decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression auto *x7a = &i; // decltype(x7a) is int* decltype(auto)*x7d = &i; // error, declared type is not plain decltype(auto)
— end example ]