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?
Reference variable is an alternate name of already existing variable. It cannot be changed to refer another variable and should be initialized at the time of declaration and cannot be NULL. The operator '&' is used to declare reference variable. The following is the syntax of reference variable.
In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
When a variable is declared as a reference, it becomes an alternative name for an existing variable. A variable can be declared as a reference by putting '&' in the declaration.
A reference variable provides a new name to the existing variable. It is de-referenced implicitly and does not need a de-referencing operator(*) to retrieve the value referenced. Whereas, to retrieve the value pointed to by a pointer we need de-referencing operator(*) which is known as explicit de-referencing.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With