20 General utilities library [utilities]

20.15 Metaprogramming and type traits [meta]

20.15.7 Relationships between types [meta.rel]

This subclause contains templates that may be used to query relationships between types at compile time.
Each of these templates shall be a Cpp17BinaryTypeTrait ([meta.rqmts]) with a base characteristic of true_­type if the corresponding condition is true, otherwise false_­type.
Table 51: Type relationship predicates [tab:meta.rel]
Template
Condition
Comments
template<class T, class U>
struct is_­same;
T and U name the same type with the same cv-qualifications
template<class Base, class Derived>
struct is_­base_­of;
Base is a base class of Derived ([class.derived]) without regard to cv-qualifiers or Base and Derived are not unions and name the same class type without regard to cv-qualifiers
If Base and Derived are non-union class types and are not possibly cv-qualified versions of the same type, Derived shall be a complete type.
[Note 1:
Base classes that are private, protected, or ambiguous are, nonetheless, base classes.
β€” end note]
template<class From, class To>
struct is_­convertible;
see below
From and To shall be complete types, cv void, or arrays of unknown bound.
template<class From, class To>
struct is_­nothrow_­convertible;
is_­convertible_­v<From, To> is true and the conversion, as defined by is_­convertible, is known not to throw any exceptions ([expr.unary.noexcept])
From and To shall be complete types, cv void, or arrays of unknown bound.
template<class T, class U>
struct is_­layout_­compatible;
T and U are layout-compatible ([basic.types])
T and U shall be complete types, cv void, or arrays of unknown bound.
template<class Base, class Derived>
struct is_­pointer_­interconvertible_­base_­of;
Derived is unambiguously derived from Base without regard to cv-qualifiers, and each object of type Derived is pointer-interconvertible ([basic.compound]) with its Base subobject, or Base and Derived are not unions and name the same class type without regard to cv-qualifiers.
If Base and Derived are non-union class types and are not (possibly cv-qualified versions of) the same type, Derived shall be a complete type.
template<class Fn, class... ArgTypes>
struct is_­invocable;
The expression INVOKE(declval<Fn>(), declval<ArgTypes>()...) is well-formed when treated as an unevaluated operand
Fn and all types in the template parameter pack ArgTypes shall be complete types, cv void, or arrays of unknown bound.
template<class R, class Fn, class... ArgTypes>
struct is_­invocable_­r;
The expression INVOKE<R>(declval<Fn>(), declval<ArgTypes>()...) is well-formed when treated as an unevaluated operand
Fn, R, and all types in the template parameter pack ArgTypes shall be complete types, cv void, or arrays of unknown bound.
template<class Fn, class... ArgTypes>
struct is_­nothrow_­invocable;
is_­invocable_­v<
Fn, ArgTypes...> is true and the expression INVOKE(declval<Fn>(), declval<ArgTypes>()...) is known not to throw any exceptions ([expr.unary.noexcept])
Fn and all types in the template parameter pack ArgTypes shall be complete types, cv void, or arrays of unknown bound.
template<class R, class Fn, class... ArgTypes>
struct is_­nothrow_­invocable_­r;
is_­invocable_­r_­v<
R, Fn, ArgTypes...> is true and the expression INVOKE<R>(declval<Fn>(), declval<ArgTypes>()...) is known not to throw any exceptions ([expr.unary.noexcept])
Fn, R, and all types in the template parameter pack ArgTypes shall be complete types, cv void, or arrays of unknown bound.
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], [special]) function call that is not an odr-use of declval in the context of the corresponding definition notwithstanding the restrictions of [declval].
[Example 1: struct B {}; struct B1 : B {}; struct B2 : B {}; struct D : private B1, private B2 {}; is_base_of_v<B, D> // true is_base_of_v<const B, D> // true is_base_of_v<B, const D> // true is_base_of_v<B, const B> // true is_base_of_v<D, B> // false is_base_of_v<B&, D&> // false is_base_of_v<B[3], D[3]> // false is_base_of_v<int, int> // false β€” end example]
The predicate condition for a template specialization is_­convertible<From, To> shall be satisfied if and only if the return expression in the following code would be well-formed, including any implicit conversions to the return type of the function: To test() { return declval<From>(); }
[Note 2:
This requirement gives well-defined results for reference types, void types, array types, and function types.
β€” end note]
Access checking is performed in a context unrelated to To and From.
Only the validity of the immediate context of the expression of the return statement ([stmt.return]) (including initialization of the returned object or reference) is considered.
[Note 3:
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]