我有一个带有可变参数模板构造函数的模板类:
template<typename T, int nb = 1>
class MyClass
{
/* ... some stuff here ... */
template<typename... Ts>
MyClass(Ts... ts)
{
/* ... some code ... */
}
}
如何定义移动构造函数
MyClass(MyClass&& source)
对于非模板化构造函数,我通常做的是:构建MyClass类型的对象tmp
,其std::swap
每个成员*this
然后我交换{{1}的每个成员与source
一起使用。现在*this*
包含了所有垃圾tmp
,我只是让我的构造函数的范围负责删除*this*
...
但是在这里我被困住了,并且不知道如何构建我的tmp
对象。
答案 0 :(得分:1)
问题是参数Ts&&...
可以匹配MyClass<T,nb>&
(即非常量)。这使得它在auto b = a;
和类似的情况下更好地匹配(因为a不是const)。
因此,您必须使用某些SFNAE魔法禁用该情况,或者提供能够做正确事情的特定重载:
#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();
}
预期产出:
hello, world
goodbye
goodbye
goodbye
答案 1 :(得分:0)
考虑使用 C++17 in_place_t
标记类型来消除采用可变参数的构造函数的歧义。那么就不需要像 Richard 的回答那样显式定义复制/移动构造函数。
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);
}
如果您没有 C++17,您可以轻松地将自己的 in_place_t
标记类型定义为空结构(但不在 std
命名空间内)。