I have a class template like this:
template <typename T>
class MyClass
{
public:
MyClass(const T & val); // First
MyClass(T&& val); // Second
};
Basically I want MyClass to be constructible from a T
whether it's an rvalue or an lvalue. Now when I have something like
const A& foo = ...;
MyClass<const A&> x(foo);
I get redefinition error for MyClass(const A & val)
.
I presume this is because T&& is a universal reference and due to reference collapsing rules, the second constructor also gets converted to having the same signature as the first.
Firstly is my understanding of the error scenario correct? secondly how can I get around this problem(I want to able the use the optimizations that move semantics provide when constructing MyClass)?
I presume this is because T&& is a universal reference ...
Incorrect. T&&
is not a universal (forwarding) reference in this case. T&&
is exactly an rvalue reference to T
. Universal/forwarding references must be deduced.
... and due to reference collapsing rules, the second constructor also gets converted to having the same signature as the first.
This is correct. Our two constructors take:
T const& ==> A const& const& ==> A const&
T&& ==> A const& && ==> A const&
hence the redefinition error.
Depending on what it is you want to do, a simple solution might be to just std::decay
T
:
template <typename T>
class MyClass
{
using DecT = typename std::decay<T>::type;
public:
MyClass(const DecT& );
MyClass(DecT&& );
};
For your example, that will still create a class with two constructors: one taking const A&
and the other taking A&&
.
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