21 Metaprogramming library [meta]

21.3 Metaprogramming and type traits [type.traits]

21.3.5 Unary type traits [meta.unary]

21.3.5.1 General [meta.unary.general]

Subclause [meta.unary] contains templates that may be used to query the properties of a type at compile time.
Each of these templates shall be a Cpp17UnaryTypeTrait ([meta.rqmts]) with a base characteristic of true_type if the corresponding condition is true, otherwise false_type.

21.3.5.2 Primary type categories [meta.unary.cat]

The primary type categories correspond to the descriptions given in subclause [basic.types] of the C++ standard.
For any given type T, the result of applying one of these templates to T and to cv T shall yield the same result.
[Note 1: 
For any given type T, exactly one of the primary type categories has a value member that evaluates to true.
β€” end note]
Table 45: Primary type category predicates [tab:meta.unary.cat]
Template
Condition
Comments
template<class T>
struct is_void;
T is void
template<class T>
struct is_null_pointer;
T is nullptr_t ([basic.fundamental])
template<class T>
struct is_integral;
T is an integral type ([basic.fundamental])
template<class T>
struct is_floating_point;
T is a floating-point type ([basic.fundamental])
template<class T>
struct is_array;
T is an array type ([basic.compound]) of known or unknown extent
Class template array ([array]) is not an array type.
template<class T>
struct is_pointer;
T is a pointer type ([basic.compound])
Includes pointers to functions but not pointers to non-static members.
template<class T>
struct is_lvalue_reference;
T is an lvalue reference type ([dcl.ref])
template<class T>
struct is_rvalue_reference;
T is an rvalue reference type ([dcl.ref])
template<class T>
struct is_member_object_pointer;
T is a pointer to data member
template<class T>
struct is_member_function_pointer;
T is a pointer to member function
template<class T>
struct is_enum;
T is an enumeration type ([basic.compound])
template<class T>
struct is_union;
T is a union type ([basic.compound])
template<class T>
struct is_class;
T is a non-union class type ([basic.compound])
template<class T>
struct is_function;
T is a function type ([basic.compound])

21.3.5.3 Composite type traits [meta.unary.comp]

These templates provide convenient compositions of the primary type categories, corresponding to the descriptions given in subclause [basic.types].
For any given type T, the result of applying one of these templates to T and to cv T shall yield the same result.
Table 46: Composite type category predicates [tab:meta.unary.comp]
Template
Condition
Comments
template<class T>
struct is_reference;
T is an lvalue reference or an rvalue reference
template<class T>
struct is_arithmetic;
T is an arithmetic type ([basic.fundamental])
template<class T>
struct is_fundamental;
T is a fundamental type ([basic.fundamental])
template<class T>
struct is_object;
T is an object type ([basic.types.general])
template<class T>
struct is_scalar;
T is a scalar type ([basic.types.general])
template<class T>
struct is_compound;
T is a compound type ([basic.compound])
template<class T>
struct is_member_pointer;
T is a pointer-to-member type ([basic.compound])

21.3.5.4 Type properties [meta.unary.prop]

These templates provide access to some of the more important properties of types.
It is unspecified whether the library defines any full or partial specializations of any of these templates.
For all of the class templates X declared in this subclause, instantiating that template with a template-argument that is a class template specialization may result in the implicit instantiation of the template argument if and only if the semantics of X require that the argument is a complete type.
For the purpose of defining the templates in this subclause, a function call expression declval<T>() for any type T is considered to be a trivial ([basic.types.general], [special]) function call that is not an odr-use ([basic.def.odr]) of declval in the context of the corresponding definition notwithstanding the restrictions of [declval].
For the purpose of defining the templates in this subclause, let VAL<T> for some type T be an expression defined as follows:
  • If T is a reference or function type, VAL<T> is an expression with the same type and value category as declval<T>().
  • Otherwise, VAL<T> is a prvalue that initially has type T.
    [Note 1: 
    If T is cv-qualified, the cv-qualification is subject to adjustment ([expr.type]).
    β€” end note]
Table 47: Type property predicates [tab:meta.unary.prop]
Template
Condition
Preconditions
template<class T>
struct is_const;
T is const-qualified ([basic.type.qualifier])
template<class T>
struct is_volatile;
T is volatile-qualified ([basic.type.qualifier])
template<class T>
struct is_trivial;
T is a trivial type ([basic.types.general])
remove_all_extents_t<T> shall be a complete type or cv void.
template<class T>
struct is_trivially_copyable;
T is a trivially copyable type ([basic.types.general])
remove_all_extents_t<T> shall be a complete type or cv void.
template<class T>
struct is_standard_layout;
T is a standard-layout type ([basic.types.general])
remove_all_extents_t<T> shall be a complete type or cv void.
template<class T>
struct is_empty;
T is a class type, but not a union type, with no non-static data members other than subobjects of zero size, no virtual member functions, no virtual base classes, and no base class B for which is_empty_v<B> is false.
If T is a non-union class type, T shall be a complete type.
template<class T>
struct is_polymorphic;
T is a polymorphic class ([class.virtual])
If T is a non-union class type, T shall be a complete type.
template<class T>
struct is_abstract;
T is an abstract class ([class.abstract])
If T is a non-union class type, T shall be a complete type.
template<class T>
struct is_final;
T is a class type marked with the class-virt-specifier final ([class.pre]).
[Note 2: 
A union is a class type that can be marked with final.
β€” end note]
If T is a class type, T shall be a complete type.
template<class T>
struct is_aggregate;
T is an aggregate type ([dcl.init.aggr])
T shall be an array type, a complete type, or cv void.
template<class T>
struct is_signed;
If is_arithmetic_v<T> is true, the same result as T(-1) < T(0); otherwise, false
template<class T>
struct is_unsigned;
If is_arithmetic_v<T> is true, the same result as T(0) < T(-1); otherwise, false
template<class T>
struct is_bounded_array;
T is an array type of known bound ([dcl.array])
template<class T>
struct is_unbounded_array;
T is an array type of unknown bound ([dcl.array])
template<class T>
struct is_scoped_enum;
T is a scoped enumeration ([dcl.enum])
template<class T, class... Args>
struct is_constructible;
For a function type T or for a cv void type T, is_constructible_v<T, Args...> is false, otherwise see below
T and all types in the template parameter pack Args shall be complete types, cv void, or arrays of unknown bound.
template<class T>
struct is_default_constructible;
is_constructible_v<T> is true.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T>
struct is_copy_constructible;
For a referenceable type T ([defns.referenceable]), the same result as is_constructible_v<T, const T&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T>
struct is_move_constructible;
For a referenceable type T, the same result as is_constructible_v<T, T&&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T, class U>
struct is_assignable;
The expression declval<T>() = declval<U>() is well-formed when treated as an unevaluated operand ([expr.context]).
Access checking is performed as if in a context unrelated to T and U.
Only the validity of the immediate context of the assignment expression is considered.
[Note 3: 
The compilation of the expression can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on.
Such side effects are not in the β€œimmediate context” and can result in the program being ill-formed.
β€” end note]
T and U shall be complete types, cv void, or arrays of unknown bound.
template<class T>
struct is_copy_assignable;
For a referenceable type T, the same result as is_assignable_v<T&, const T&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T>
struct is_move_assignable;
For a referenceable type T, the same result as is_assignable_v<T&, T&&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T, class U>
struct is_swappable_with;
The expressions swap(declval<T>(), declval<U>()) and swap(declval<U>(), declval<T>()) are each well-formed when treated as an unevaluated operand ([expr.context]) in an overload-resolution context for swappable values ([swappable.requirements]).
Access checking is performed as if in a context unrelated to T and U.
Only the validity of the immediate context of the swap expressions is considered.
[Note 4: 
The compilation of the expressions can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on.
Such side effects are not in the β€œimmediate context” and can result in the program being ill-formed.
β€” end note]
T and U shall be complete types, cv void, or arrays of unknown bound.
template<class T>
struct is_swappable;
For a referenceable type T, the same result as is_swappable_with_v<T&, T&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T>
struct is_destructible;
Either T is a reference type, or T is a complete object type for which the expression declval<U&>().~U() is well-formed when treated as an unevaluated operand ([expr.context]), where U is remove_all_extents_t<T>.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T, class... Args>
struct
is_trivially_constructible;
is_constructible_v<T,
Args...> is true and the variable definition for is_constructible, as defined below, is known to call no operation that is not trivial ([basic.types.general], [special]).
T and all types in the template parameter pack Args shall be complete types, cv void, or arrays of unknown bound.
template<class T>
struct is_trivially_default_constructible;
is_trivially_constructible_v<T> is true.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T>
struct is_trivially_copy_constructible;
For a referenceable type T, the same result as is_trivially_constructible_v<T, const T&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T>
struct is_trivially_move_constructible;
For a referenceable type T, the same result as is_trivially_constructible_v<T, T&&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T, class U>
struct is_trivially_assignable;
is_assignable_v<T, U> is true and the assignment, as defined by is_assignable, is known to call no operation that is not trivial ([basic.types.general], [special]).
T and U shall be complete types, cv void, or arrays of unknown bound.
template<class T>
struct is_trivially_copy_assignable;
For a referenceable type T, the same result as is_trivially_assignable_v<T&, const T&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T>
struct is_trivially_move_assignable;
For a referenceable type T, the same result as is_trivially_assignable_v<T&, T&&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T>
struct is_trivially_destructible;
is_destructible_v<T> is true and remove_all_extents_t<T> is either a non-class type or a class type with a trivial destructor.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T, class... Args>
struct is_nothrow_constructible;
is_constructible_v<T, Args...> is true and the variable definition for is_constructible, as defined below, is known not to throw any exceptions ([expr.unary.noexcept]).
T and all types in the template parameter pack Args shall be complete types, cv void, or arrays of unknown bound.
template<class T>
struct is_nothrow_default_constructible;
is_nothrow_constructible_v<T> is true.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T>
struct is_nothrow_copy_constructible;
For a referenceable type T, the same result as is_nothrow_constructible_v<T, const T&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T>
struct is_nothrow_move_constructible;
For a referenceable type T, the same result as is_nothrow_constructible_v<T, T&&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T, class U>
struct is_nothrow_assignable;
is_assignable_v<T, U> is true and the assignment is known not to throw any exceptions ([expr.unary.noexcept]).
T and U shall be complete types, cv void, or arrays of unknown bound.
template<class T>
struct is_nothrow_copy_assignable;
For a referenceable type T, the same result as is_nothrow_assignable_v<T&, const T&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T>
struct is_nothrow_move_assignable;
For a referenceable type T, the same result as is_nothrow_assignable_v<T&, T&&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T, class U>
struct is_nothrow_swappable_with;
is_swappable_with_v<T, U> is true and each swap expression of the definition of is_swappable_with<T, U> is known not to throw any exceptions ([expr.unary.noexcept]).
T and U shall be complete types, cv void, or arrays of unknown bound.
template<class T>
struct is_nothrow_swappable;
For a referenceable type T, the same result as is_nothrow_swappable_with_v<T&, T&>, otherwise false.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T>
struct is_nothrow_destructible;
is_destructible_v<T> is true and the indicated destructor is known not to throw any exceptions ([expr.unary.noexcept]).
T shall be a complete type, cv void, or an array of unknown bound.
template<class T>
struct is_implicit_lifetime;
T is an implicit-lifetime type ([basic.types.general]).
T shall be an array type, a complete type, or cv void.
template<class T>
struct has_virtual_destructor;
T has a virtual destructor ([class.dtor])
If T is a non-union class type, T shall be a complete type.
template<class T>
struct has_unique_object_representations;
For an array type T, the same result as has_unique_object_representations_v<remove_all_extents_t<T>>, otherwise see below.
T shall be a complete type, cv void, or an array of unknown bound.
template<class T, class U>
struct reference_constructs_from_temporary;
T is a reference type, and the initialization T t(VAL<U>); is well-formed and binds t to a temporary object whose lifetime is extended ([class.temporary]).
Access checking is performed as if in a context unrelated to T and U.
Only the validity of the immediate context of the variable initialization is considered.
[Note 5: 
The initialization can result in effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on.
Such effects are not in the β€œimmediate context” and can result in the program being ill-formed.
β€” end note]
T and U shall be complete types, cv void, or arrays of unknown bound.
template<class T, class U>
struct reference_converts_from_temporary;
T is a reference type, and the initialization T t = VAL<U>; is well-formed and binds t to a temporary object whose lifetime is extended ([class.temporary]).
Access checking is performed as if in a context unrelated to T and U.
Only the validity of the immediate context of the variable initialization is considered.
[Note 6: 
The initialization can result in effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on.
Such effects are not in the β€œimmediate context” and can result in the program being ill-formed.
β€” end note]
T and U shall be complete types, cv void, or arrays of unknown bound.
[Example 1: is_const_v<const volatile int> // true is_const_v<const int*> // false is_const_v<const int&> // false is_const_v<int[3]> // false is_const_v<const int[3]> // true β€” end example]
[Example 2: remove_const_t<const volatile int> // volatile int remove_const_t<const int* const> // const int* remove_const_t<const int&> // const int& remove_const_t<const int[3]> // int[3] β€” end example]
[Example 3: // Given: struct P final { }; union U1 { }; union U2 final { }; // the following assertions hold: static_assert(!is_final_v<int>); static_assert(is_final_v<P>); static_assert(!is_final_v<U1>); static_assert(is_final_v<U2>); β€” end example]
The predicate condition for a template specialization is_constructible<T, Args...> shall be satisfied if and only if the following variable definition would be well-formed for some invented variable t:
T t(declval<Args>()...);
[Note 7: 
These tokens are never interpreted as a function declaration.
β€” end note]
Access checking is performed as if in a context unrelated to T and any of the Args.
Only the validity of the immediate context of the variable initialization is considered.
[Note 8: 
The evaluation of the initialization can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on.
Such side effects are not in the β€œimmediate context” and can result in the program being ill-formed.
β€” end note]
The predicate condition for a template specialization has_unique_object_representations<T> shall be satisfied if and only if:
  • T is trivially copyable, and
  • any two objects of type T with the same value have the same object representation, where
    • two objects of array or non-union class type are considered to have the same value if their respective sequences of direct subobjects have the same values, and
    • two objects of union type are considered to have the same value if they have the same active member and the corresponding members have the same value.
The set of scalar types for which this condition holds is implementation-defined.
[Note 9: 
If a type has padding bits, the condition does not hold; otherwise, the condition holds true for integral types.
β€” end note]