26377

How to detect whether a class has a move constructor?

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 &&.

Answer1:

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:

    <li>All classes have a copy constructor.</li> <li>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.</li> <li>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.</li> <li>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).</li> <li>SFINAE is used to to detect the member swap.
      <li>If the member swap is present, resize + back + swap is used to add a new element to the vector.</li> <li>Otherwise, push_back is used.</li> </ul></li> </ul>

      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

Recommend

  • How sys.exc_info() works?
  • keep selected rows when changing dataset in shiny DT datatable
  • How to make an Ionic content scroll
  • What is lua_len() alternative in Lua 5.1?
  • How does `std::terminate` know to treat `std::exception`s specially?
  • Call a macro with parameters : Python win32com API
  • Criterion causing memory consumption to explode, no CAFs in sight
  • Getting short path in python
  • How to read piped content in C?
  • How do I signal completion of my dataflow?
  • RxJava debounce by arbitrary value
  • Convert Type Decimal to Hex (string) in .NET 3.5
  • Parsing a CSV string while ignoring commas inside the individual columns
  • Avoid links criss cross / overlap in d3.js using force layout
  • Using $this when not in object context
  • How do I fake an specific browser client when using Java's Net library?
  • How reduce the height of an mschart by breaking up the y-axis
  • AES padding and writing the ciphertext to a disk file
  • Possible to stop flickering java tooltip in heavyweight mode?
  • output of program is not same as passed argument
  • Perl system calls when running as another user using sudo
  • How to model a transition system with SPIN
  • Convert array of 8 bytes to signed long in C++
  • Jquery - Jquery Wysiwyg return html as a string
  • Akka Routing: Reply's send to router ends up as dead letters
  • Arrays break string types in Julia
  • Linker errors when using intrinsic function via function pointer
  • Python: how to group similar lists together in a list of lists?
  • WPF Applying a trigger on binding failure
  • Java static initializers and reflection
  • LevelDB C iterator
  • unknown Exception android
  • EntityFramework adding new object to nested object collection
  • Checking variable from a different class in C#
  • Django query for large number of relationships
  • Why is Django giving me: 'first_name' is an invalid keyword argument for this function?
  • How can I use `wmic` in a Windows PE script?
  • failed to connect to specific WiFi in android programmatically
  • How to push additional view controllers onto NavigationController but keep the TabBar?
  • How can I use threading to 'tick' a timer to be accessed by other threads?