To remove a reference:
#include <type_traits>
static_assert(std::is_same<int, std::remove_reference<int&>::type>::value, "wat");
In your case:
template <typename T>
auto doSomething(const T& foo)
-> typename std::remove_reference<decltype(foo.bar())>::type
{
return foo.bar();
}
Just to be clear, note that as written returning a reference is just fine:
#include <type_traits>
struct f
{
int& bar() const
{
static int i = 0;
return i;
}
};
template <typename T>
auto doSomething(const T& foo)
-> decltype(foo.bar())
{
return foo.bar();
}
int main()
{
f x;
return doSomething(x);
}
The returned reference can simply be passed on without error. Your example in the comment is where it becomes important and useful:
template <typename T>
auto doSomething(const T& foo)
-> decltype(foo.bar())
{
return foo.bar() + 1; // oops
}