std::is_move_constructible, std::is_trivially_move_constructible, std::is_nothrow_move_constructible
Header: <type_traits>
If T is not a complete type, (possibly cv-qualified) void, or an array of unknown bound, the behavior is undefined.
# Declarations
template< class T >
struct is_move_constructible;
(since C++11)
template< class T >
struct is_trivially_move_constructible;
(since C++11)
template< class T >
struct is_nothrow_move_constructible;
(since C++11)
# Notes
Types without a move constructor, but with a copy constructor that accepts const T& arguments, satisfy std::is_move_constructible.
Move constructors are usually noexcept, since otherwise they are unusable in any code that provides strong exception guarantee.
In many implementations, std::is_nothrow_move_constructible also checks if the destructor throws because it is effectively noexcept(T(arg)). Same applies to std::is_trivially_move_constructible, which, in these implementations, also requires that the destructor is trivial: GCC bug 51452, LWG issue 2116.
# Example
#include <string>
#include <type_traits>
struct Ex1
{
std::string str; // member has a non-trivial but non-throwing move constructor
};
static_assert(std::is_move_constructible_v<Ex1>);
static_assert(!std::is_trivially_move_constructible_v<Ex1>);
static_assert(std::is_nothrow_move_constructible_v<Ex1>);
struct Ex2
{
int n;
Ex2(Ex2&&) = default; // trivial and non-throwing
};
static_assert(std::is_move_constructible_v<Ex2>);
static_assert(std::is_trivially_move_constructible_v<Ex2>);
static_assert(std::is_nothrow_move_constructible_v<Ex2>);
struct NoMove1
{
// prevents implicit declaration of default move constructor;
// however, the class is still move-constructible because its
// copy constructor can bind to an rvalue argument
NoMove1(const NoMove1&) {}
};
static_assert(std::is_move_constructible_v<NoMove1>);
static_assert(!std::is_trivially_move_constructible_v<NoMove1>);
static_assert(!std::is_nothrow_move_constructible_v<NoMove1>);
struct NoMove2
{
// Not move-constructible since the lvalue reference
// can't bind to the rvalue argument
NoMove2(NoMove2&) {}
};
static_assert(!std::is_move_constructible_v<NoMove2>);
static_assert(!std::is_trivially_move_constructible_v<NoMove2>);
static_assert(!std::is_nothrow_move_constructible_v<NoMove2>);
int main() {}
# Defect reports
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| LWG 2196 | C++11 | the behavior was unclear if T&& cannot be formed | the value produced is false in this case |