不同于复制构造函数的移动构造函数的静态断言

Static assertion for a move constructor different from the copy constructor

想象一下,我有一个 class A,移动成本低,复制成本高。它可能看起来像

class A {
  public: 
    [...]

  private:
    HeavyClass m;
};

对于这个 class,我想要一个静态验证 class (1) 是移动可构造的并且 (2) 不简单的使用拷贝构造函数进行move构造, 与移动构造函数是否显式声明无关。

这可能吗?

至于为什么我会喜欢这个,请考虑以下示例:首先,class 自动生成移动构造函数并按预期运行。然后,有人更改class并添加了一个析构函数,这导致移动构造函数不被隐式生成,而是使用复制构造函数。

因此,static_assert 将是理想的选择,但似乎 is_move_constructibleis_trivially_move_constructible 的 none 在这里很有帮助。

此外,我知道可以为所有此类 class 设置 A(A&&) = default;,但带有 static_assert 的解决方案会更干净,并允许在外部进行检查class 定义(f.i。在依赖此 class 的其他项目中)。

编辑:
我不想禁止复制构造,我只是想确保移动构造函数没有使用它...

如果您可以将 A 更改为间接寻址,您可以执行以下操作:

template <bool>
struct MoveOnly {
    MoveOnly() = default;
    ~MoveOnly() = default;
    MoveOnly(const MoveOnly&) = delete;
    MoveOnly(MoveOnly&&) = default;
    MoveOnly& operator=(const MoveOnly&) = delete;
    MoveOnly& operator=(MoveOnly&&) = default;
};

template <> struct MoveOnly<false> {};

template <bool check = false>
class A_Impl : MoveOnly<check> {
public: 
    // ... as ~A_Impl() {}
    // ...
private:
    HeavyClass m;
};

using A = A_Impl<false>; // Normal case

// The check
static_assert(std::is_move_constructible<A_Impl<true>>::value, "");

Demo

复制构造函数和复制赋值运算符的生成是deprecated声明析构函数时。不需要静态断言或模板,这是现代 C++ 的一部分。

解决方案就是启用弃用警告

如果您还没有将警告转化为错误,也将其转化为错误。

这样您就不必记得在整个过程中添加静态断言。此外,您仍然可以添加析构函数,拥有 non-moveable 成员并继承 non-moveables ,只要您不复制或移动此类对象的任何实例 .不适用的限制没有意义。

有了这个设置你可以尝试把这段代码添加到你class(一个典型的回归)

virtual ~A() = default;

如果您现在尝试移动复制A的实例,那么编译将失败。

示例错误消息来自 clang-3.9 -Werror -Wdeprecated

main.cpp:13:13: error: definition of implicit copy assignment
operator for 'A' is deprecated because it has a user-declared 
destructor [-Werror,-Wdeprecated]
    virtual ~A() = default;
            ^
main.cpp:21:7: note: implicit copy assignment operator for
'A' first required here
    b = std::move(a);
      ^
1 error generated.

如果你创建了一个 A 的实例并简单地通过 const reference 传递它,那么你的编译器就不会抱怨了。

这是一个完全通用的维护问题。理想情况下,我们希望为此找到一个通用的解决方案。 手动 添加断言是一个糟糕的解决方案。它容易出错、容易忘记、耗时并且降低代码的可读性。

一个通用的解决方案是使用静态分析器为所有 类.

强制执行 Rule of Zero 如果您的编译器支持,

Link to SO question about this. However, adding compiler options 是更好的解决方案。