如何检测一个类是否有移动构造函数?

时间:2017-02-23 18:10:04

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

我想检测(并使用std::enable_if中的结果)C ++类是否定义了移动构造函数。

以下程序打印MOVE,因此使用std::is_move_constructible不是这样做的方法:

#include <stdio.h>
#include <type_traits>
class C {
 public:
  C() { puts("C()"); }
  C(int) { puts("C(int)"); }
  ~C() { puts("~C()"); }
  C(const C&) { puts("C(const C&)"); }
  // C(C&&) { puts("C(C&&)"); }
  C& operator=(const C&) { puts("C="); return *this; }
};
int main(int argc, char** argv) {
  (void)argc; (void)argv;
  if (std::is_move_constructible<C>::value) puts("MOVE");
  return 0;
}

我需要一个仅在我取消注释包含MOVE的行时打印&&的程序。

1 个答案:

答案 0 :(得分:4)

简短回答:这是不可能的。

更多细节,基于@TobySpeight的评论:

如果该类不包含C(C&&) = delete;,则无法检测它是否包含C(C&&) { ... }std::is_move_constructible<C>::value在任何一种情况下均为真,并且没有其他方式检测它。

可以检测到C(C&&) = delete;的存在:如果std::is_move_constructible<C>::value存在,则C(C&&) = delete;为false。

this answer to "Understanding std::is_move_constructible"中的更多解释。

为了避免在std::vector::push_back中进行慢速复制,不需要检测用户定义的移动构造函数。根据@ NirFriedman的评论,这是另一种选择:

  • 所有类都有一个复制构造函数。
  • 旧(C ++ 98)类有成员交换和0参数构造函数(可以由编译器隐式生成),并且它们没有用户定义的移动构造函数。
  • 新的(C ++ 11)类没有成员交换(但它们可以有命名空间级交换或朋友交换),并且它们具有用户定义的移动构造函数。
  • 小类(我们不关心复制构造函数的速度,它总是足够快)可能有一个用户定义的移动构造函数。他们也可能有成员交换(但他们不应该,为了速度)。如果他们有成员交换,他们也有一个0参数构造函数(可以由编译器隐式生成)。
  • SFINAE用于检测成员交换。
    • 如果存在成员交换,则使用resize + back + swap向向量添加新元素。
    • 否则,使用push_back。

对于旧类,这将使用成员交换(快速)。对于新类,它将使用移动构造函数(快速,也快一点)。对于小类,它将使用复制构造函数(假设对于小类来说足够快)或移动构造函数(如果可用)。

以下是我使用成员交换检测的快速std::vector::push_back的最终解决方案:https://github.com/pts/fast_vector_append/blob/master/fast_vector_append.h