[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<T>()), where *N* is the pack ofsize_t template arguments of the specialization ofindex_sequence denoted bymake_index_sequence<tuple_size_v<remove_reference_t<T>>>[.](#3.sentence-1)

Table [56](#tab:meta.rel) — Type relationship predicates [[tab:meta.rel]](./tab:meta.rel)  

| [ð](#tab:meta.rel-row-1)<br>**Template** | **Condition** | **Comments** |
| --- | --- | --- |
| [ð](#tab:meta.rel-row-2)<br>template<class T, class U>   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)<br>template<class Base, class Derived>   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)<br>[*Note [1](#tab:meta.rel-row-3-column-3-note-1)*:<br>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)<br>template<class Base, class Derived>   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)<br>[*Note [2](#tab:meta.rel-row-4-column-3-note-2)*:<br>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*]<br>[*Note [3](#tab:meta.rel-row-4-column-3-note-3)*:<br>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)<br>template<class From, class To>   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)<br>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]](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)<br>template<class T, class U>   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)<br>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]](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)<br>template<class Fn, class... ArgTypes>   struct is_invocable; | The expression *INVOKE*(declval<Fn>(), declval<ArgTypes>()...) ([[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)<br>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[.](#tab:meta.rel-row-10-column-3-sentence-1) |
| [ð](#tab:meta.rel-row-11)<br>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]](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)<br>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]](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)<br>template<class Fn, class Tuple>   struct is_applicable; | [*tuple-like*](tuple.like#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]")<Tuple> is true and  the expression  *INVOKE*(declval<Fn>(), *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)<br>template<class Fn, class Tuple>   struct is_nothrow_applicable; | is_applicable_v<   Fn, Tuple> is true and  the expression *INVOKE*(declval<Fn>(), *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<T>() 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<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*]

[6](#6)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L1936)

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 [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*]
