Preventing non-const lvalues from resolving to rvalue reference instead of const lvalue reference
c++, metaprogramming, rvalue-reference, templates
Solution
When you have a templated function like this you almost never want to overload. The `T&&` parameter is a catch anything parameter. And you can use it to get any behavior you want out of one overload.
#include <iostream>
#include <vector>
using namespace std;
template <class T>
void display()
{
typedef typename remove_reference<T>::type Tr;
typedef typename remove_cv<Tr>::type Trcv;
if (is_const<Tr>::value)
cout << "const ";
if (is_volatile<Tr>::value)
cout << "volatile ";
std::cout << typeid(Trcv).name();
if (is_lvalue_reference<T>::value)
std::cout << '&';
else if (is_rvalue_reference<T>::value)
std::cout << "&&";
std::cout << '\n';
}
template <class T>
void foo(T&& t)
{
display<T>();
}
int main()
{
vector<int> x;
vector<int> const cx;
foo(x); // vector<int>&
foo(vector<int>()); // vector<int>
foo(cx); // const vector<int>&
}
Problem
I'm having trouble overloading a function to take a value either by const reference or, if it is an rvalue, an rvalue reference. The problem is that my non-const lvalues are binding to the rvalue version of the function. I'm doing this in VC2010. ``` #include <iostream> #include <vector> using namespace std; template <class T> void foo(const T& t) {cout << "void foo(const T&)" << endl;} template <class T> void foo(T&& t) {cout << "void foo(T&&)" << endl;} int main() { vector<int> x; foo(x); // void foo(T&&) ????? foo(vector<int>()); // void foo(T&&) } ``` The priority seems to be to deduce foo(x) as ``` foo< vector<int> & >(vector<int>& && t) ``` instead of ``` foo< vector<int> >(const vector<int>& t) ``` I tried replacing the rvalue-reference version with ``` void foo(typename remove_reference<T>::type&& t) ``` but this only had the effect of causing everything to resolve to the const-lvalue reference version. How do I prevent this behaviour? And why is this the default anyway - it seems so dangerous given that rvalue-references are allowed to be modified, this leaves me with an unexpectedly modified local variable. EDIT: Just added non-template versions of the functions, and they work as expected. Making the function a template changes the overload resolution rules? That is .. really frustrating! ``` void bar(const vector<int>& t) {cout << "void bar(const vector<int>&)" << endl;} void bar(vector<int>&& t) {cout << "void bar(vector<int>&&)" << endl;} bar(x); // void bar(const vector<int>&) bar(vector<int>()); // void bar(vector<int>&&) ```