如何检测 class 是否有移动构造函数?
How to detect whether a class has a move constructor?
我想检测(并在 std::enable_if
中使用结果)C++ class 是否定义了移动构造函数。
下面的程序打印 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
只有当我取消注释包含 &&
.
的行时
简答:不可能。
更多细节,基于@TobySpeight 的评论:
如果class不包含C(C&&) = delete;
,则无法检测它是否包含C(C&&) { ... }
:无论哪种情况,std::is_move_constructible<C>::value
都为真,并且没有其他方法可以检测到它。
可以检测到 C(C&&) = delete;
的存在:std::is_move_constructible<C>::value
是假的当且仅当 C(C&&) = delete;
存在。
更多解释见this answer to "Understanding std::is_move_constructible
"。
为了避免在 std::vector::push_back
中进行缓慢的复制,没有必要检测用户定义的移动构造函数。这是替代方案,基于@NirFriedman 的评论:
- 所有 classes 都有一个复制构造函数。
- 旧 (C++98) classes 具有成员交换和 0 参数构造函数(可以由编译器隐式生成),并且它们没有用户定义的移动构造函数。
- 新的 (C++11) classes 没有成员交换(但它们可以有命名空间级交换或友元交换),并且它们有一个用户定义的移动构造函数.
- 小型 classes(我们不关心复制构造函数的速度,它总是足够快)可能有一个用户定义的移动构造函数。他们也可能有成员交换(但为了速度他们不应该)。如果它们有成员交换,它们也有一个 0 参数构造函数(可以由编译器隐式生成)。
- SFINAE 用于检测成员交换。
- 如果存在成员swap,resize + back + swap用于向vector中添加一个新元素。
- 否则,使用push_back。
对于旧的 classes,这将使用成员交换(快速)。对于新的 classes,它将使用移动构造函数(快,也快一点)。对于小型 classes,它将使用复制构造函数(假设对于小型 classes 足够快)或移动构造函数(如果可用)。
这是我的快速 std::vector::push_back
成员交换检测的最终解决方案:https://github.com/pts/fast_vector_append/blob/master/fast_vector_append.h
我想检测(并在 std::enable_if
中使用结果)C++ class 是否定义了移动构造函数。
下面的程序打印 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
只有当我取消注释包含 &&
.
简答:不可能。
更多细节,基于@TobySpeight 的评论:
如果class不包含C(C&&) = delete;
,则无法检测它是否包含C(C&&) { ... }
:无论哪种情况,std::is_move_constructible<C>::value
都为真,并且没有其他方法可以检测到它。
可以检测到 C(C&&) = delete;
的存在:std::is_move_constructible<C>::value
是假的当且仅当 C(C&&) = delete;
存在。
更多解释见this answer to "Understanding std::is_move_constructible
"。
为了避免在 std::vector::push_back
中进行缓慢的复制,没有必要检测用户定义的移动构造函数。这是替代方案,基于@NirFriedman 的评论:
- 所有 classes 都有一个复制构造函数。
- 旧 (C++98) classes 具有成员交换和 0 参数构造函数(可以由编译器隐式生成),并且它们没有用户定义的移动构造函数。
- 新的 (C++11) classes 没有成员交换(但它们可以有命名空间级交换或友元交换),并且它们有一个用户定义的移动构造函数.
- 小型 classes(我们不关心复制构造函数的速度,它总是足够快)可能有一个用户定义的移动构造函数。他们也可能有成员交换(但为了速度他们不应该)。如果它们有成员交换,它们也有一个 0 参数构造函数(可以由编译器隐式生成)。
- SFINAE 用于检测成员交换。
- 如果存在成员swap,resize + back + swap用于向vector中添加一个新元素。
- 否则,使用push_back。
对于旧的 classes,这将使用成员交换(快速)。对于新的 classes,它将使用移动构造函数(快,也快一点)。对于小型 classes,它将使用复制构造函数(假设对于小型 classes 足够快)或移动构造函数(如果可用)。
这是我的快速 std::vector::push_back
成员交换检测的最终解决方案:https://github.com/pts/fast_vector_append/blob/master/fast_vector_append.h