The following small example shows my problem:
template<class T> struct X
{
static void xxx(T& x) { }
static void xxx(T&& x) { }
};
int main(int argc, char** argv)
{
int x = 9;
X<int>::xxx(x); // OK.
X<int&>::xxx(x); // ERROR!
return 0;
}
Error message (GCC):
error: ‘static void X::xxx(T&&) [with T = int&]’ cannot be overloaded
error: with ‘static void X::xxx(T&) [with T = int&]’
Why? T = int& —> Is T& replaced by int&& in static void xxx(T& x)?
If the answer to the question is yes, then:
T&is not a lvalue-reference and it becomes a rvalue-reference!- And the following code should work:
But it didn’t:
template<class T> struct X
{
static void xxx(T& x) { }
};
int main(int argc, char** argv)
{
X<int&>::xxx(2); // ERROR!
return 0;
}
Error Message (GCC):
error: no matching function for call to ‘X::xxx(int)’
note: candidates are: static void X::xxx(T&) [with T = int&]
Then T& with T = int& is not equal to T&& and is not a rvalue-reference. but if it is not, why the first example not working? (it’s a recursive problem!)
But the similar problem didn’t occur for pointer types:
#include <iostream>
template<class T> struct X
{
static void xxx(T* x) { std::cout << **x << std::endl; }
};
int main(int argc, char** argv)
{
int x = 10;
int* xx = &x;
X<int*>::xxx(&xx); // OK. call X<int*>::xxx(int**)
return 0;
}
Why references are different in this behavior?
The C++11 language standard has an explanation of how this works at §8.3.2[dcl.ref]/6 (reformatted for readability):
Let’s consider your example (I’ve renamed your
Tto beTRso it matches the language above):If we try instantiating
XwithTR = int&(so,T = int), the instantiations ofxxxare as follows:In the first case, we attempt to create an "lvalue reference to
TR," which becomes an "lvalue reference toT."Tisint, so the parameter type becomesint&.In the second case, we attempt to create an "rvalue reference to
TR," which becomesTR, which isint&.The parameter type is the same for both overloads, hence the error.