2017-02-23 182 views
2

我想检测(并使用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只有当我去掉含有&&行。

+2

你想“has_user_defined_move_ctor”基本上? – Borgleader

+6

由于右值可以绑定到常量引用,除非实际删除右值构造函数,即C(C &&)= delete;',否则该类的用户不会看到区别。你知道是否有移动构造函数可以解决真正的问题吗? –

+0

是的,我想要has_user_defined_move_ctor。真正的问题是有效地追加到一个std :: vector:如果类有一个移动构造函数,我想调用push_back;否则,如果类已经交换,我想调用resize + back + swap,否则我想调用push_back(只有最后一个push_back是缓慢的,因为它正在做一个大副本)。我想使它适用于C++ 98库中的类(我无法在不更改其源代码的情况下添加缺少的移动构造函数,并且这会很麻烦)。 – pts

回答

2

简答:这是不可能的。

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

如果类不包含C(C&&) = delete;,那么它是不可能的,检测是否含有C(C&&) { ... }与否:std::is_move_constructible<C>::value会在两种情况下是真实的,没有其他方法可以检测到它。

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

更多说明请见this answer to "Understanding std::is_move_constructible"

为了避免在std::vector::push_back中慢速复制,检测用户定义的移动构造函数是不必要的。这是基于@ NirFriedman的评论的替代方案:

  • 所有类都有一个复制构造函数。
  • Old(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

相关问题