Please consider the following code:
class CMyClass {};
template<class T>
void func(T&& param) {
if (std::is_same<CMyClass, std::decay<T>::type>::value)
std::cout << "param is a CMyClass\n";
if (std::is_same<T, CMyClass&>::value)
std::cout << "param is a CMyClass reference\n";
else if (std::is_same<T, CMyClass&&>::value)
std::cout << "param is a CMyClass r-value reference\n";
else if (std::is_same<T, const CMyClass&>::value)
std::cout << "param is a const CMyClass reference\n";
else if (std::is_same<T, const CMyClass&&>::value)
std::cout << "param is a const CMyClass r-value reference\n";
else if (std::is_same<T, const CMyClass>::value)
std::cout << "param is a constant CMyClass\n";
else if (std::is_same<T, CMyClass>::value)
std::cout << "param is a CMyClass\n";
else
std::cout << "param is not a CMyClass\n";
}
CMyClass mc3;
func(std::move(mc3));
The output from this little program is
param is a CMyClass
param is a CMyClass
Why has the type of mc3 not been deduced to be an r-value reference please?
I can't find a good dupe for this even though one must exist somewhere, sorry.
The deduction rules for:
template <class T>
void foo(T&& )
in the context of a call foo(expr)
are:
expr
is an lvalue of type U
, then T
is deduced as U&
and the type T&&
is U&
, due to reference collapsing. expr
is an rvalue of type U
, then T
is deduced as U
the type T&&
is U&&
, due to reference collapsing. In your example, std::move(mc3)
is an rvalue (specifically an xvalue) of type CMyClass
. Hence, T
is deduced as CMyClass
. This check:
else if (std::is_same<T, CMyClass&&>::value)
std::cout << "param is a CMyClass r-value reference\n";
will almost never be true as T
will never deduce as an rvalue reference type. It could be specifically provided as such:
func<CMyClass&&>(std::move(mc3));
but that's an unlikely usage. What you can do instead is check:
else if (std::is_same<T&&, CMyClass&&>::value)
// ~~~~
That will handle all cases where the argument is an rvalue. Indeed, if you simply always check for T&&
, that will handle all of your cases properly.
Why has the type of mc3 not been deduced to be an r-value reference please?
If param
is an rvalue , T
is a non-reference inside func
, and T&&
is an rvalue reference . Here's an example that empirically shows what T
means in the body of a function that takes a forwarding reference :
template <typename T>
void func(T&& x)
{
std::is_same<T, something>{}; // (0)
std::is_same<T&&, something>{}; // (1)
}
In the case of (0) :
T
is T
when an rvalue is passed to func
. (*) T
is T&
for when an lvalue is passed to func
. In the case of (1) :
T&&
is T&&
when an rvalue is passed to func
. T&&
is T&
when an lvalue is passed to func
. If you use std::is_same<T&&, CMyClass>::value
, you should either get a T&
or T&&
.
(*) : note that the term "is" is inaccurate - the various meanings of T
inside func
depend on template argument deduction and reference collapsing .
In short:
T
is deduced as:
T&
if x
is an lvalue .
T
otherwise.
Due to reference collapsing , T&&
is:
T&
if x
is an lvalue . ( T& &&
-> T&
)
T&&
otherwise. ( T&& &&
-> T&&
)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.