问题
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