Reputation: 1131
I have an template class with a variadic template constructor:
template<typename T, int nb = 1>
class MyClass
{
/* ... some stuff here ... */
template<typename... Ts>
MyClass(Ts... ts)
{
/* ... some code ... */
}
}
How do I define the move constructor
MyClass(MyClass&& source)
For non templated constructors what I usually do is : build an object tmp
of type MyClass for which I std::swap
every member with *this
and then I swap every member of source
with *this*
. Now tmp
contains all the garbage *this*
had and I just let the scope of my constructor taking care of deleting tmp
...
But here I'm stuck and don't know how to construct my MyClass tmp(???)
object.
Upvotes: 3
Views: 1181
Reputation: 29219
Consider using the C++17 in_place_t
tag type to disambiguate your constructor taking variadic arguments. Then there is no need to explicitly define the copy/move constructors like in Richard's answer.
template<typename T, int nb = 1>
class MyClass
{
/* ... some stuff here ... */
template<typename... Ts>
MyClass(std::in_place_t, Ts... ts)
{
/* ... some code ... */
}
}
int main()
{
MyClass foo(std::in_place, 123, 456);
MyClass bar(foo);
}
If you don't have C++17, you can easily define your own in_place_t
tag type as an empty struct (but not within the std
namespace).
Upvotes: 0
Reputation: 69902
The problem is that the argument Ts&&...
can match a MyClass<T,nb>&
(i.e. non-const). This makes it a better match in the case of auto b = a;
and similar (because a is not const).
So you'll either have to disable that case with some SFNAE magic or provide a specific overload that does the right thing:
#include <memory>
#include <string>
#include <iostream>
template<typename T, int nb = 1>
class MyClass
{
/* ... some stuff here ... */
public:
template<typename... Ts>
MyClass(Ts&&... ts)
: _pstr(std::make_shared<std::string>(std::forward<Ts>(ts)...))
{
}
// match the specific case, and force a copy
MyClass(MyClass<T, nb>& r)
: MyClass(static_cast<const MyClass<T, nb>&>(r))
{}
// and now we must match all copy/move operations
MyClass(const MyClass<T, nb>&) = default;
MyClass& operator=(const MyClass<T, nb>&) = default;
MyClass(MyClass<T, nb>&&) = default;
MyClass& operator=(MyClass<T, nb>&&) = default;
void print() const {
std::cout << *_pstr << std::endl;
}
private:
std::shared_ptr<std::string> _pstr;
};
// test
int main()
{
auto a = MyClass<int>("hello, world");
auto b = a;
auto c = MyClass<int>("goodbye");
auto d = c;
b = c;
a.print();
b.print();
c.print();
d.print();
}
expected output:
hello, world
goodbye
goodbye
goodbye
Upvotes: 2