看一下下面的代码示例,该示例使用类似于uncopiableboost::noncopyable类:

#include <vector>

class uncopiable {
    using self = uncopiable;
protected:
    uncopiable() {}
    ~uncopiable() {}
    uncopiable(const self&) = delete;
    self& operator=(const self&) = delete;
};

struct A {
    struct B : uncopiable {
        using self = B;

        B() {
        }

        B(B&&) = default;
        self& operator=(B&&) = default;

        ~B() {
        }
    };

    A() { v.emplace_back(); }
    ~A() {}

private:
    std::vector<B> v;
};

int main () {}

因为我只想移动内部类,所以我明确地将其移动构造函数和赋值运算符指定为默认值,而且由于我听说在这种情况下指定所有“特殊成员函数”是一种好习惯,因此我继承了它来自uncopiable。问题是每个编译器编译都会失败,并且会显示类似以下错误消息的内容(此消息摘自clang消息):



可以通过删除继承来解决此问题(仍然不会创建复制操作)。但是写复制操作以在类之后显式删除也是可以的。

我的问题是:为什么会发生?是否可以认为是通过继承辅助类来禁用构造函数/赋值运算符的缺陷?

最佳答案

问题是您的uncopiable类不可移动。因此,派生类的default move构造函数/赋值运算符尝试使用delete d复制版本。

static_assert(std::is_move_constructible<uncopiable>::value, "");  // fails
static_assert(std::is_move_assignable<uncopiable>::value, "");     // fails

原因是§12.8¶9:



将复制运算符或赋值运算符声明为delete d仍视为声明它。

解决方案当然是声明uncopiable的移动操作。
uncopiable(uncopiable&&) noexcept = default;
uncopiable& operator=(uncopiable&&) noexcept = default;

注意move operations should usually be declared noexcept 。特别是如果您想像示例中那样在std::vector中使用类型。

10-04 14:40