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 &&
.
A move constructor allows the resources owned by an rvalue object to be moved into an lvalue without creating its copy. An rvalue is an expression that does not have any memory address, and an lvalue is an expression with a memory address.
If a copy constructor, copy-assignment operator, move constructor, move-assignment operator, or destructor is explicitly declared, then: No move constructor is automatically generated. No move-assignment operator is automatically generated.
std::move is actually just a request to move and if the type of the object has not a move constructor/assign-operator defined or generated the move operation will fall back to a copy.
To correct this, remove the move constructor completely. In the case of the class, once a copy constructor is present (user defined), the move is implicitly not generated anyway (move constructor and move assignment operator).
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:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With