繁体   English   中英

执行明确默认的特殊成员函数生成

[英]Enforcing explicitly defaulted special member function generation

在C ++ 11中,如果自动阻止了隐式生成,则可以显式地默认特殊成员函数。

但是,显式默认默认特殊成员函数只会撤消由于手动声明某些其他特殊成员函数(复制操作,析构函数等)而导致的隐式删除,它不会强制编译器生成函数,并且代码被认为是即使实际上不能生成函数,也要很好地形成。

请考虑以下情形:

struct A
{
    A ()         = default;
    A (const A&) = default;
    A (A&&)      = delete;  // Move constructor is deleted here
};

struct B
{
    B ()         = default;
    B (const B&) = default;
    B (B&&)      = default; // Move constructor is defaulted here

    A a;
};

B中的移动构造函数不会由编译器生成,因为这样做会导致编译错误(删除A的移动构造函数)。 在没有明确删除A的构造函数的情况下,B的移动构造函数将按预期生成(复制A,而不是移动它)。

试图移动这样的对象将默默使用复制构造函数:

B b;
B b2 (std::move(b)); // Will call B's copy constructor

有没有办法强制编译器生成函数或发出编译错误,如果它不能? 如果没有这种保证,如果单个已删除的构造函数可以禁用整个对象层次结构的移动,则很难依赖默认的移动构造函数。

有一种方法可以检测类似A类型。 但仅当类型明确删除了移动构造函数时。 如果将移动构造函数隐式生成为已删除,则它将不参与重载解析。 这就是为什么B可以移动,即使A不是。 B default为移动构造函数,这意味着它被隐式删除,因此发生复制。

因此, B是可构造的。 但是, A不是。 所以这是一个简单的问题:

struct B
{
    static_assert(is_move_constructible<A>::value, "Oops...");

    B ()         = default;
    B (const B&) = default;
    B (B&&)      = default; // Move constructor is defaulted here

    A a;
};

现在,没有一般方法可以使任何包含只复制类型的类型执行您想要的操作。 也就是说,您必须单独对每种类型进行静态断言; 你不能在默认移动构造函数中放置一些语法来尝试移动B失败。

其原因部分在于向后兼容性。 想想所有声明用户定义的拷贝构造函数的前C ++ 11代码。 根据C ++ 11中移动构造函数生成的规则,所有这些都会删除移动构造函数。 这意味着任何形式的代码T t = FuncReturningTByValue(); 即使它通过调用复制构造函数在C ++ 98/03中运行得很好,也会失败。 因此,如果无法生成移动构造函数,则通过复制而不是移动来解决此问题。

但是因为= default意味着“做你通常会做的事情”,它还包括这种特殊的重载解析行为,它忽略了隐式删除的移动构造函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM