#include <iostream>
using namespace std;
namespace mine {
template <typename T>
struct remove_rval {
using type = T;
};
template <typename T>
struct remove_rval<T&&> {
using type = T;
};
template <typename T>
void g(const T& = typename remove_rval<T>::type())
cout << __PRETTY_FUNCTION__ << endl;
}
}
int main()
{
mine::g<int&&>(); // doesn't work, because of explicit template?
const int& i2 = mine::remove_rval<int&&>::type(); // works, sanity check
return 0;
}
The function template I wrote fails to compile. From my understanding of c , you can assign an rvalue to a constant lvalue reference. But, in this situation, it is like the deduced type disregards the 'const' qualifier when assigning the function default value. Why is this?
CodePudding user response:
void g(const T& = typename remove_rval<T>::type())
Reference collapsing rules make const T&
equal to U&
when T = U&&
. Lvalue-references can't bind to temporaries like remove_rval<T>::type()
. You can instead simply pass int
as a template argument and the parameter's type will correctly be const int&
.
CodePudding user response:
From dcl.ref/p6:
If a typedef-name ([dcl.typedef], [temp.param]) or a decltype-specifier ([dcl.type.decltype]) denotes a type TR that is a reference to a type T, an attempt to create the type lvalue reference to cv
TR
creates the type lvalue reference toT
, while an attempt to create the type rvalue reference to cv TR creates the typeTR
.
Thus in your example, when T = int&&
:
const T&
becomes T&= int&
and not const T& = const int&
according to the above quoted statement. And since we can't bind an rvalue like remove_rval<T>::type()
to a non-const lvalue reference, you get the mentioned error.