[meta.rel] # 21 Metaprogramming library [[meta]](./#meta) ## 21.3 Metaprogramming and type traits [[type.traits]](type.traits#meta.rel) ### 21.3.8 Relationships between types [meta.rel] [1](#1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L1744) The templates specified in Table [56](#tab:meta.rel "Table 56: Type relationship predicates") may be used to query relationships between types at compile time[.](#1.sentence-1) [2](#2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L1748) Each of these templates shall be a[*Cpp17BinaryTypeTrait*](meta.rqmts#:Cpp17BinaryTypeTrait "21.3.2 Requirements [meta.rqmts]") ([[meta.rqmts]](meta.rqmts "21.3.2 Requirements")) with a base characteristic oftrue_type if the corresponding condition is true, otherwisefalse_type[.](#2.sentence-1) [3](#3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L1755) Let *ELEMS-OF*(T) be the parameter packget<*N*>(declval()), where *N* is the pack ofsize_t template arguments of the specialization ofindex_sequence denoted bymake_index_sequence>>[.](#3.sentence-1) Table [56](#tab:meta.rel) — Type relationship predicates [[tab:meta.rel]](./tab:meta.rel) | [🔗](#tab:meta.rel-row-1)
**Template** | **Condition** | **Comments** | | --- | --- | --- | | [🔗](#tab:meta.rel-row-2)
template struct [is_same](#lib:is_same "21.3.8 Relationships between types [meta.rel]"); | T and U name the same type with the same cv-qualifications | | | [🔗](#tab:meta.rel-row-3)
template struct is_base_of; | Base is a base class of Derived ([[class.derived]](class.derived "11.7 Derived classes")) 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[.](#tab:meta.rel-row-3-column-3-sentence-1)
[*Note [1](#tab:meta.rel-row-3-column-3-note-1)*:
Base classes that are private, protected, or ambiguous are, nonetheless, base classes[.](#tab:meta.rel-row-3-column-3-sentence-2) — *end note*] | | [🔗](#tab:meta.rel-row-4)
template struct is_virtual_base_of; | Base is a virtual base class of Derived ([[class.mi]](class.mi "11.7.2 Multiple base classes")) without regard to cv-qualifiers[.](#tab:meta.rel-row-4-column-2-sentence-1) | If Base and Derived are non-union class types, Derived shall be a complete type[.](#tab:meta.rel-row-4-column-3-sentence-1)
[*Note [2](#tab:meta.rel-row-4-column-3-note-2)*:
Virtual base classes that are private, protected, or ambiguous are, nonetheless, virtual base classes[.](#tab:meta.rel-row-4-column-3-sentence-2) — *end note*]
[*Note [3](#tab:meta.rel-row-4-column-3-note-3)*:
A class is never a virtual base class of itself[.](#tab:meta.rel-row-4-column-3-sentence-3) — *end note*] | | [🔗](#tab:meta.rel-row-5)
template struct is_convertible; | *see below* | From and To shall be complete types, cv void, or arrays of unknown bound[.](#tab:meta.rel-row-5-column-3-sentence-1) | | [🔗](#tab:meta.rel-row-6)
template struct is_nothrow_convertible; | is_convertible_v is true and the conversion, as defined by is_convertible, is known not to throw any exceptions ([[expr.unary.noexcept]](expr.unary.noexcept "7.6.2.7 noexcept operator")) | From and To shall be complete types, cv void, or arrays of unknown bound[.](#tab:meta.rel-row-6-column-3-sentence-1) | | [🔗](#tab:meta.rel-row-7)
template struct is_layout_compatible; | T and U are layout-compatible ([[basic.types.general]](basic.types.general#term.layout.compatible.type "6.9.1 General")) | T and U shall be complete types, cv void, or arrays of unknown bound[.](#tab:meta.rel-row-7-column-3-sentence-1) | | [🔗](#tab:meta.rel-row-8)
template 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]](basic.compound "6.9.4 Compound types")) with its Base subobject, or Base and Derived are not unions and name the same class type without regard to cv-qualifiers[.](#tab:meta.rel-row-8-column-2-sentence-1) | 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[.](#tab:meta.rel-row-8-column-3-sentence-1) | | [🔗](#tab:meta.rel-row-9)
template struct is_invocable; | The expression *INVOKE*(declval(), declval()...) ([[func.require]](func.require "22.10.4 Requirements")) is well-formed when treated as an unevaluated operand ([[expr.context]](expr.context#term.unevaluated.operand "7.2.3 Context dependence")) | Fn and all types in the template parameter pack ArgTypes shall be complete types, cv void, or arrays of unknown bound[.](#tab:meta.rel-row-9-column-3-sentence-1) | | [🔗](#tab:meta.rel-row-10)
template struct is_invocable_r; | The expression *INVOKE*(declval(), declval()...) 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[.](#tab:meta.rel-row-10-column-3-sentence-1) | | [🔗](#tab:meta.rel-row-11)
template struct is_nothrow_invocable; | is_invocable_v< Fn, ArgTypes...> is true and the expression *INVOKE*(declval(), declval()...) is known not to throw any exceptions ([[expr.unary.noexcept]](expr.unary.noexcept "7.6.2.7 noexcept operator")) | Fn and all types in the template parameter pack ArgTypes shall be complete types, cv void, or arrays of unknown bound[.](#tab:meta.rel-row-11-column-3-sentence-1) | | [🔗](#tab:meta.rel-row-12)
template struct is_nothrow_invocable_r; | is_invocable_r_v< R, Fn, ArgTypes...> is true and the expression *INVOKE*(declval(), declval()...) is known not to throw any exceptions ([[expr.unary.noexcept]](expr.unary.noexcept "7.6.2.7 noexcept operator")) | Fn, R, and all types in the template parameter pack ArgTypes shall be complete types, cv void, or arrays of unknown bound[.](#tab:meta.rel-row-12-column-3-sentence-1) | | [🔗](#tab:meta.rel-row-13)
template struct is_applicable; | [*tuple-like*](tuple.like#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") is true and the expression *INVOKE*(declval(), *ELEMS-OF*(Tuple)...) is well-formed when treated as an unevaluated operand[.](#tab:meta.rel-row-13-column-2-sentence-1) | Fn and Tuple shall be complete types, cv void, or arrays of unknown bound[.](#tab:meta.rel-row-13-column-3-sentence-1) | | [🔗](#tab:meta.rel-row-14)
template struct is_nothrow_applicable; | is_applicable_v< Fn, Tuple> is true and the expression *INVOKE*(declval(), *ELEMS-OF*(Tuple)...) is known not to throw any exceptions ([[expr.unary.noexcept]](expr.unary.noexcept "7.6.2.7 noexcept operator"))[.](#tab:meta.rel-row-14-column-2-sentence-1) | Fn and Tuple shall be complete types, cv void, or arrays of unknown bound[.](#tab:meta.rel-row-14-column-3-sentence-1) | [4](#4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L1908) For the purpose of defining the templates in this subclause, a function call expression declval() for any type T is considered to be a trivial ([[depr.meta.types]](depr.meta.types#term.trivial.type "D.13 Deprecated type traits"), [[special]](special "11.4.4 Special member functions")) function call that is not an odr-use ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3 One-definition rule")) of declval in the context of the corresponding definition notwithstanding the restrictions of [[declval]](declval "22.2.6 Function template declval")[.](#4.sentence-1) [5](#5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L1916) [*Example [1](#example-1)*: struct B {};struct B1 : B {};struct B2 : B {};struct D : private B1, private B2 {}; is_base_of_v // true is_base_of_v // true is_base_of_v // true is_base_of_v // true is_base_of_v // false is_base_of_v // false is_base_of_v // false is_base_of_v // false — *end example*] [6](#6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L1936) The predicate condition for a template specialization is_convertible 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();} [*Note [4](#note-4)*: This requirement gives well-defined results for reference types, array types, function types, and cv void[.](#6.sentence-2) — *end note*] Access checking is performed in a context unrelated to To and From[.](#6.sentence-3) Only the validity of the immediate context of the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") of the return statement ([[stmt.return]](stmt.return "8.8.4 The return statement")) (including initialization of the returned object or reference) is considered[.](#6.sentence-4) [*Note [5](#note-5)*: 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[.](#6.sentence-5) Such side effects are not in the “immediate context” and can result in the program being ill-formed[.](#6.sentence-6) — *end note*]