利用移动语义自动隐式生成ctors

时间:2016-09-14 18:46:20

标签: c++ c++11 constructor default move-semantics

让我们有一个包含n个字段的类。每个字段都可以移动。那么我们是否必须明确定义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);

2 个答案:

答案 0 :(得分:3)

您可以通过使用完美转发模板构造函数来解决它:

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_ifstatic_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

答案 1 :(得分:0)

您没有错误地定义特殊成员函数,复制/移动构造函数没有按类成员定义,它是根据类定义的。

而不是

class_name(const member_1&, ..., const member_n&)
class_name(const member_1&&, ..., const member_n&&)

您必须将复制/移动构造函数定义为:

class_name(const class_name&) // copy-constructor
class_name(class_name&&) // move constructor

并在其中,使用复制/移动语义。见c++draft class.copy