Reputation: 8033
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!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?
Upvotes: 7
Views: 1868
Reputation: 354979
The C++11 language standard has an explanation of how this works at §8.3.2[dcl.ref]/6 (reformatted for readability):
If a typedef, a type template-parameter, or a decltype-specifier denotes a type
TR
that is a reference to a typeT
,
- an attempt to create the type "lvalue reference to cv
TR
" creates the type "lvalue reference toT
"- an attempt to create the type "rvalue reference to cv
TR
" creates the typeTR
.
Let's consider your example (I've renamed your T
to be TR
so it matches the language above):
template<class TR> struct X
{
static void xxx(TR& x) { }
static void xxx(TR&& x) { }
};
If we try instantiating X
with TR = int&
(so, T = int
), the instantiations of xxx
are as follows:
static void xxx(TR& x) { } --> static void xxx(int& x) { }
static void xxx(TR&& x) { } --> static void xxx(int& x) { }
In the first case, we attempt to create an "lvalue reference to TR
," which becomes an "lvalue reference to T
." T
is int
, so the parameter type becomes int&
.
In the second case, we attempt to create an "rvalue reference to TR
," which becomes TR
, which is int&
.
The parameter type is the same for both overloads, hence the error.
Upvotes: 12