How can I coerce a function in a templated class to return a reference to a member variable using auto/decltype?
Here's a trivialized example of what I'm trying to do. Suppose you've got a templated class that stores something in a private member variable, a_
as follows:
#include <iostream>
template <typename T>
class A
{
private:
T a_;
public:
A(T a) : a_(a) {}
// 1. Return const reference to a_
const T & get() const { return a_; }
// 2. Return non-const reference to a_
T & get() { return a_; }
};
int main(int argc, char *argv[])
{
A<int> a(3);
const auto & a1 = a.get(); // 1. Return const reference to a_
//a1 = 4; // Shouldn't compile
std::cout << "Value of a = " << a.get() << std::endl;
auto & a2 = a.get(); // 2. Return non-const reference to a_
a2 = 5;
std::cout << "Value of a = " << a.get() << std::endl;
return 0;
}
The expected/desired output is:
Value of a = 3
Value of a = 5
But now, suppose I want the compiler to deduce the type returned by the const and non-const get()
functions in A<T>
and I want to ensure both calls return references to a_
.
My best guess is currently:
template <typename T>
class A
{
private:
T a_;
public:
A(T a) : a_(a) {}
// 1. Return const reference to a_
const auto get() const -> std::add_lvalue_reference<const decltype(a_)>::type
{
return a_;
}
// 2. Return non-const reference to a_
auto get() -> std::add_lvalue_reference<decltype(a_)>::type
{
return a_;
}
};
but that fails to compile. The first error given by GCC is:
decltype.cpp:11:29: error: expected type-specifier
decltype.cpp:11:26: error: expected ‘;’ at end of member declaration
decltype.cpp:11:29: error: ‘add_lvalue_reference’ in namespace ‘std’ does not name a type
The motivation for this lies outwith my distilled example code, but stems from an attempt to reduce the number of parameters a template takes when one (or more) of those parameters is used solely to specify a return type which the compiler should (I think) be able to deduce by itself. Note: in the real world, the return type of get()
is not that of a_
, but is the return type of some function f(a_)
which I know to be deducible by the compiler. Thus my need for auto/decltype in this example.
The thing that's puzzling me is that the compiler can deduce the return type correctly using near-identical code in a non-templated class:
class A
{
private:
int a_;
public:
A(int a) : a_(a) {}
// 1. Return const reference to a_
const auto get() const -> std::add_lvalue_reference<const decltype(a_)>::type
{
return a_;
}
// 2. Return non-const reference to a_
auto get() -> std::add_lvalue_reference<decltype(a_)>::type
{
return a_;
}
};
Any help to understand what I'm missing will be greatly appreciated.
Details:
Centos 6.5
gcc (GCC) 4.7.2 20121015 (Red Hat 4.7.2-5)
const auto get() const
For a trailing-return-type, you may only useauto
before the function's name, notconst auto
. – dypconst auto
, since it also applies to variable declarations (auto
is replaced). However, look at [dcl.fct]/2 which forbids it explicitly – dypT D
whereD
has the form [grammar for function declaration with trailing return type],T
shall be the single type-specifierauto
." – T.C.decltype(auto)
. – dypconst auto
isn't needed in that context anyway; unlike with variable declarations usingauto
, function-auto does maintain cv-qualification. – JAB