利用移动语义自动隐式生成 ctors
Automatic implicit generation of ctors utilising move semantics
让我们有一个包含 n 个字段的 class。每个字段都可以移动。那么我们是否必须显式定义 2^n 个构造函数?
n=2 的例子:
struct A{
std::vector<B> a;
std::shared_ptr<B> b;
A(std::vector<B> &a, std::shared_ptr<B> &b):a(a),b(b){};
A(std::vector<B> &a, std::shared_ptr<B> &&b):a(a),b(std::move(b)){};
A(std::vector<B> &&a, std::shared_ptr<B> &b):a(std::move(a)),b(b){};
A(std::vector<B> &&a, std::shared_ptr<B> &&b):a(std::move(a)),b(std::move(b)){};
};
....
A aaa({{},{}}, shared_ptr<B>(new B()));
std::shared_ptr<B> b = ....;
A bbb({{},{}}, b);
您错误地定义了特殊成员函数,copy/move 构造函数不是根据 class 成员定义的,它是根据 class.[=13= 定义的]
而不是
class_name(const member_1&, ..., const member_n&)
class_name(const member_1&&, ..., const member_n&&)
您必须将 copy/move 构造函数定义为:
class_name(const class_name&) // copy-constructor
class_name(class_name&&) // move constructor
并在其中使用 copy/move 语义。见 c++draft class.copy
你可以通过一个完美的转发模板构造函数来解决这个问题:
struct A {
std::vector<B> a;
std::shared_ptr<B> b;
template <typename AA, typename BB> A(AA&& a, BB&& b) :
a(std::forward<AA>(a)), b(std::forward<BB>(b)) { }
};
如果您需要更严格的参数类型要求,您还可以添加enable_if
或static_assert
。
这里稍微解释一下完美转发的工作原理:
void func1(int&&) { }
template <typename A> void func2(A&& t) {
func3(t);
func4(std::forward<A>(t);
}
template <typename B> void func3(B&&) { }
template <typename C> void func4(C&&) { }
int foo;
const int bar;
func1(foo); // ERROR
func1(bar); // ERROR
func1(std::move(foo)); // OK
func2(foo); // OK, A = int&, B = int&, C = int&
func2(bar); // OK, A = const int&, B = const int&, C = const int&
func2(std::move(foo)); // OK, A = int&&, B = int&, C = int&& <- note how && collapses to & without std::forward
让我们有一个包含 n 个字段的 class。每个字段都可以移动。那么我们是否必须显式定义 2^n 个构造函数?
n=2 的例子:
struct A{
std::vector<B> a;
std::shared_ptr<B> b;
A(std::vector<B> &a, std::shared_ptr<B> &b):a(a),b(b){};
A(std::vector<B> &a, std::shared_ptr<B> &&b):a(a),b(std::move(b)){};
A(std::vector<B> &&a, std::shared_ptr<B> &b):a(std::move(a)),b(b){};
A(std::vector<B> &&a, std::shared_ptr<B> &&b):a(std::move(a)),b(std::move(b)){};
};
....
A aaa({{},{}}, shared_ptr<B>(new B()));
std::shared_ptr<B> b = ....;
A bbb({{},{}}, b);
您错误地定义了特殊成员函数,copy/move 构造函数不是根据 class 成员定义的,它是根据 class.[=13= 定义的]
而不是
class_name(const member_1&, ..., const member_n&)
class_name(const member_1&&, ..., const member_n&&)
您必须将 copy/move 构造函数定义为:
class_name(const class_name&) // copy-constructor
class_name(class_name&&) // move constructor
并在其中使用 copy/move 语义。见 c++draft class.copy
你可以通过一个完美的转发模板构造函数来解决这个问题:
struct A {
std::vector<B> a;
std::shared_ptr<B> b;
template <typename AA, typename BB> A(AA&& a, BB&& b) :
a(std::forward<AA>(a)), b(std::forward<BB>(b)) { }
};
如果您需要更严格的参数类型要求,您还可以添加enable_if
或static_assert
。
这里稍微解释一下完美转发的工作原理:
void func1(int&&) { }
template <typename A> void func2(A&& t) {
func3(t);
func4(std::forward<A>(t);
}
template <typename B> void func3(B&&) { }
template <typename C> void func4(C&&) { }
int foo;
const int bar;
func1(foo); // ERROR
func1(bar); // ERROR
func1(std::move(foo)); // OK
func2(foo); // OK, A = int&, B = int&, C = int&
func2(bar); // OK, A = const int&, B = const int&, C = const int&
func2(std::move(foo)); // OK, A = int&&, B = int&, C = int&& <- note how && collapses to & without std::forward