Namespaces
Variants

std:: disjunction

From cppreference.net
Metaprogramming library
Type traits
Type categories
(C++11)
(C++11) ( DR* )
Type properties
(C++11)
(C++11)
(C++14)
(C++11) (deprecated in C++26)
(C++11) ( until C++20* )
(C++11) (deprecated in C++20)
(C++11)
Type trait constants
Metafunctions
disjunction
(C++17)
(C++17)
Supported operations
Relationships and property queries
Type modifications
Type transformations
(C++11) (deprecated in C++23)
(C++11) (deprecated in C++23)
(C++11)
(C++11) ( until C++20* ) (C++17)

Compile-time rational arithmetic
Compile-time integer sequences
Definiert im Header <type_traits>
template < class ... B >
struct disjunction ;
(seit C++17)

Bildet die logische Disjunktion der Type-Traits B... , was effektiv eine logische OR-Operation auf der Sequenz von Traits durchführt.

Die Spezialisierung std :: disjunction < B1, ..., BN > hat eine öffentliche und eindeutige Basis, die

  • falls sizeof... ( B ) == 0 , std:: false_type ; andernfalls
  • der erste Typ Bi in B1, ..., BN für den bool ( Bi :: value ) == true , oder BN falls kein solcher Typ existiert.

Die Member-Namen der Basisklasse, außer disjunction und operator= , werden nicht verborgen und sind in disjunction eindeutig verfügbar.

Disjunktion ist kurzschließend: wenn es ein Template-Typenargument Bi gibt mit bool ( Bi :: value ) ! = false , dann erfordert die Instanziierung von disjunction < B1, ..., BN > :: value nicht die Instanziierung von Bj :: value für j > i .

Wenn das Programm Spezialisierungen für std::disjunction oder std::disjunction_v hinzufügt, ist das Verhalten undefiniert.

Inhaltsverzeichnis

Template-Parameter

B... - jedes Template-Argument Bi für das Bi :: value instanziiert wird, muss als Basisklasse verwendbar sein und ein Member value definieren, das in bool konvertierbar ist

Hilfsvariablen-Template

template < class ... B >
constexpr bool disjunction_v = disjunction < B... > :: value ;
(seit C++17)

Mögliche Implementierung

template<class...>
struct disjunction : std::false_type {};
template<class B1>
struct disjunction<B1> : B1 {};
template<class B1, class... Bn>
struct disjunction<B1, Bn...>
    : std::conditional_t<bool(B1::value), B1, disjunction<Bn...>>  {};

Hinweise

Eine Spezialisierung von disjunction erbt nicht notwendigerweise von std:: true_type oder std:: false_type : sie erbt einfach vom ersten B , dessen ::value , explizit konvertiert zu bool , true ist, oder vom letzten B , wenn alle zu false konvertieren. Zum Beispiel ist std :: disjunction < std:: integral_constant < int , 2 > , std:: integral_constant < int , 4 >> :: value gleich 2 .

Die Kurzschluss-Instanziierung unterscheidet disjunction von Fold-Ausdrücken : Ein Fold-Ausdruck wie ( ... || Bs :: value ) instanziiert jedes B in Bs , während std :: disjunction_v < Bs... > die Instanziierung stoppt, sobald der Wert bestimmt werden kann. Dies ist besonders nützlich, wenn der spätere Typ aufwändig zu instanziieren ist oder einen schwerwiegenden Fehler verursachen kann, wenn er mit dem falschen Typ instanziiert wird.

Feature-Test Makro Wert Standard Feature
__cpp_lib_logical_traits 201510L (C++17) Logische Operator-Typ-Traits

Beispiel

#include <cstdint>
#include <string>
#include <type_traits>
// values_equal<a, b, T>::value ist true genau dann wenn a == b.
template<auto V1, decltype(V1) V2, typename T>
struct values_equal : std::bool_constant<V1 == V2>
{
    using type = T;
};
// default_type<T>::value ist immer true
template<typename T>
struct default_type : std::true_type
{
    using type = T;
};
// Jetzt können wir Disjunktion wie eine switch-Anweisung verwenden:
template<int I>
using int_of_size = typename std::disjunction< //
    values_equal<I, 1, std::int8_t>,           //
    values_equal<I, 2, std::int16_t>,          //
    values_equal<I, 4, std::int32_t>,          //
    values_equal<I, 8, std::int64_t>,          //
    default_type<void>                         // muss zuletzt stehen!
    >::type;
static_assert(sizeof(int_of_size<1>) == 1);
static_assert(sizeof(int_of_size<2>) == 2);
static_assert(sizeof(int_of_size<4>) == 4);
static_assert(sizeof(int_of_size<8>) == 8);
static_assert(std::is_same_v<int_of_size<13>, void>);
// Die Überprüfung, ob Foo aus double konstruierbar ist, wird einen schwerwiegenden Fehler verursachen
struct Foo
{
    template<class T>
    struct sfinae_unfriendly_check { static_assert(!std::is_same_v<T, double>); };
    template<class T>
    Foo(T, sfinae_unfriendly_check<T> = {});
};
template<class... Ts>
struct first_constructible
{
    template<class T, class...Args>
    struct is_constructible_x : std::is_constructible<T, Args...>
    {
        using type = T;
    };
    struct fallback
    {
        static constexpr bool value = true;
        using type = void; // Typ, der zurückgegeben wird, wenn nichts gefunden wurde
    };
    template<class... Args>
    using with = typename std::disjunction<is_constructible_x<Ts, Args...>...,
                                           fallback>::type;
};
// OK, is_constructible<Foo, double> nicht instanziiert
static_assert(std::is_same_v<first_constructible<std::string, int, Foo>::mit<double>,
                             int>);
static_assert(std::is_same_v<first_constructible<std::string, int>::mit<>, std::string>);
static_assert(std::is_same_v<first_constructible<std::string, int>::mit<const char*>,
                             std::string>);
static_assert(std::is_same_v<first_constructible<std::string, int>::mit<void*>, void>);
int main() {}

Siehe auch

(C++17)
logische NOT-Metafunktion
(Klassentemplate)
variadische logische UND-Metafunktion
(Klassentemplate)