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
Défini dans l'en-tête <type_traits>
template < class ... B >
struct disjunction ;
(depuis C++17)

Forme la disjonction logique des traits de type B... , effectuant efficacement un OU logique sur la séquence de traits.

La spécialisation std :: disjunction < B1, ..., BN > possède une base publique et non ambiguë qui est

  • si sizeof... ( B ) == 0 , std:: false_type ; sinon
  • le premier type Bi dans B1, ..., BN pour lequel bool ( Bi :: value ) == true , ou BN s'il n'existe pas un tel type.

Les noms des membres de la classe de base, à l'exception de disjunction et operator= , ne sont pas masqués et sont disponibles sans ambiguïté dans disjunction .

La disjonction est à court-circuit : s'il existe un argument de type template Bi avec bool ( Bi :: value ) ! = false , alors l'instanciation de disjunction < B1, ..., BN > :: value ne nécessite pas l'instanciation de Bj :: value pour j > i .

Si le programme ajoute des spécialisations pour std::disjunction ou std::disjunction_v , le comportement est indéfini.

Table des matières

Paramètres du modèle

B... - chaque argument de template Bi pour lequel Bi :: value est instancié doit être utilisable comme classe de base et définir le membre value qui est convertible en bool

Modèle de variable d'assistance

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

Implémentation possible

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...>>  {};

Notes

Une spécialisation de disjunction n'hérite pas nécessairement de std:: true_type ou de std:: false_type : elle hérite simplement du premier B dont la valeur ::value , convertie explicitement en bool , est true , ou du tout dernier B lorsque tous se convertissent en false . Par exemple, std :: disjunction < std:: integral_constant < int , 2 > , std:: integral_constant < int , 4 >> :: value vaut 2 .

L'instanciation en court-circuit différencie disjunction des expressions de repli : une expression de repli comme ( ... || Bs :: value ) instancie chaque B dans Bs , tandis que std :: disjunction_v < Bs... > arrête l'instanciation dès que la valeur peut être déterminée. Ceci est particulièrement utile si le type suivant est coûteux à instancier ou peut provoquer une erreur grave lorsqu'il est instancié avec le mauvais type.

Macro de test de fonctionnalité Valeur Norme Fonctionnalité
__cpp_lib_logical_traits 201510L (C++17) Traits de type d'opérateurs logiques

Exemple

#include <cstdint>
#include <string>
#include <type_traits>
// values_equal<a, b, T>::value est vrai si et seulement si 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 est toujours vrai
template<typename T>
struct default_type : std::true_type
{
    using type = T;
};
// Maintenant nous pouvons utiliser la disjonction comme une instruction switch :
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>                         // doit être le dernier !
    >::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>);
// vérifier si Foo est constructible à partir de double provoquera une erreur fatale
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; // type à retourner si rien n'est trouvé
    };
    template<class... Args>
    using with = typename std::disjunction<is_constructible_x<Ts, Args...>...,
                                           fallback>::type;
};
// OK, is_constructible<Foo, double> non instancié
static_assert(std::is_same_v<first_constructible<std::string, int, Foo>::avec<double>,
                             int>);
static_assert(std::is_same_v<first_constructible<std::string, int>::avec<>, std::string>);
static_assert(std::is_same_v<first_constructible<std::string, int>::avec<const char*>,
                             std::string>);
static_assert(std::is_same_v<first_constructible<std::string, int>::avec<void*>, void>);
int main() {}

Voir aussi

(C++17)
métafonction logique NON
(modèle de classe)
métafonction logique ET variadique
(modèle de classe)