利用移动语义自动生成构造函数的隐式构造

3

假设我们有一个包含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个回答

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

为什么在原型中使用AA&& a?这个函数在lvalue引用的情况下也能工作吗? - KOLANICH
1
通过模板类型参数,“&&”具有特殊含义:它会让编译器推断模板参数和传递给函数的参数完全相同的类型(包括所有限定符)。 - Dmitry
我终于成功修复了回复更新中的所有错别字 :) 请检查。 - Dmitry
谢谢。这篇关于引用折叠的文章也很有用。 - KOLANICH

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


我并不是想复制A类的对象,而是想使用rvalues构造该类而不进行复制。 - KOLANICH
A aaa({{},{}}, std::shared_ptr<B>(new B())); 或者 std::shared_ptr<B> b = ....; A bbb({{},{}}, b); - KOLANICH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接