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)
Just to mention it, you don't actually have to use std::add_lvalue_reference
to get the behaviour you want. This works just as well and is more readable in my book.
template <typename T>
class A {
private:
T a_;
public:
A(T a) : a_(a) {}
const auto get() const -> const decltype(a_) & {
return a_;
}
auto get() -> decltype(a_) & {
return a_;
}
};
int main() {
A<int> a(1);
cout << a.get() << endl;
a.get() = 2;
cout << a.get() << endl;
}