How to detect whether a class has a move constructor?

爱⌒轻易说出口 提交于 2019-12-23 20:53:06

问题


I'd like to detect (and use the result in std::enable_if) whether a C++ class has a move constructor defined.

The following program prints MOVE, so using std::is_move_constructible is not the way to do it:

#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;
}

I need a program which prints MOVE only if I uncomment the line containing the &&.


回答1:


Short answer: it's impossible.

Some more details, based on the comment by @TobySpeight:

If the class doesn't contain C(C&&) = delete;, then it's impossible to detect whether it contains C(C&&) { ... } or not: std::is_move_constructible<C>::value will be true in either case, and there is no other way to detect it.

The presence of C(C&&) = delete; can be detected: std::is_move_constructible<C>::value is false iff C(C&&) = delete; is present.

More explanation in this answer to "Understanding std::is_move_constructible".

To avoid slow copying in std::vector::push_back, detecting a user-defined move constructor is not necessary. This is the alternative, based on @NirFriedman's comment:

  • All classes have a copy constructor.
  • Old (C++98) classes have a member swap and 0-argument constructor (can be implicitly generated by the compiler), and they don't have a user-defined move constructor.
  • New (C++11) classes don't have a member swap (but they can have a namespace-level swap or a friend swap), and they have a user-defined move constructor.
  • Small classes (for which we don't care about the speed of the copy constructor, it's always fast enough) may have a user-defined move constructor. They also may have a member swap (but they shouldn't, for speed). If they have a member swap, they also have a 0-argument constructor (can be implicitly generated by the compiler).
  • SFINAE is used to to detect the member swap.
    • If the member swap is present, resize + back + swap is used to add a new element to the vector.
    • Otherwise, push_back is used.

For old classes, this will use the member swap (fast). For new classes, it will use the move constructor (fast, also a little bit faster). For small classes, it will use the copy constructor (assumed to be fast enough for small classes) or the move constructor (if available).

Here is my final solution for a fast std::vector::push_back with member swap detection: https://github.com/pts/fast_vector_append/blob/master/fast_vector_append.h



来源:https://stackoverflow.com/questions/42423146/how-to-detect-whether-a-class-has-a-move-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!