# std::disjunction

< cpp‎ | types

定义于头文件 `<type_traits>` |  |
template<class... B> struct disjunction; | (1) | (C++17 起)

组成类型特性 `B...` 的逻辑析取，等效地在特性序列上进行逻辑或。

特化 std::disjunction<B1, ..., BN> 有一个公开且无歧义的基类，即

- 若 sizeof...(B) == 0 ，则为 std::false_type ；否则
- 若 `B1, ..., BN` 中有 bool(Bi::value) == true ，则为首个 `Bi` ，或者若无这种类型则为 `BN` 。

不隐藏 `disjunction` 和 `operator=` 以外的基类成员名，而它们在 `disjunction` 中无歧义地可用。

析取是短路的：若存在模板类型参数 `Bi` 满足 bool(Bi::value) != false，则实例化 disjunction<B1, ..., BN>::value 不要求 `j > i` 的 Bj::value 的实例化。

添加 `disjunction` 或 `disjunction_v` 的特化的程序行为未定义。

### 模板形参

B... | - | 每个要实例化 Bi::value 的模板参数 `Bi` 必须可用作基类，且定义了可转换到 bool 的成员 `value`

### 辅助变量模板

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

### 可能的实现

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

### 注解

`disjunction` 的特化不需要继承自 std::true_type 或 std::false_type ：它简单地继承自首个 `B` ，其 `::value` 在显式转换为 `bool` 后为 true ，或在它们都转换为 false 时继承自最后的 B 。例如， std::disjunction<std::integral_constant<int, 2>, std::integral_constant<int, 4>>::value 为 2 。

`disjunction` 的短路实例化异于折叠表达式：如 (... || Bs::value) 的折叠表达式实例化 `Bs` 中的每个 `B` ，而 std::disjunction_v<Bs...> 一旦能确定值就停止实例化。这在之后的类型实例化代价高昂，或以错误的类型实例化能导致硬错误时特别有用。

### 示例

{{example|code=

    #include <type_traits>
    #include <cstdint>
    #include <string>

    // values_equal<a, b, T>::value 为 true 当且仅当 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 始终为 true
    template <typename T>
    struct default_type : std::true_type {
      using type = T;
    };

    // 现在我们可以像 switch 语句一样使用 disjunction ：
    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>                          // 必须在最后！
        >::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>);

    // 检查 Foo 是否可从 double 构造将导致硬错误
    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; // 若找不到则用于返回的类型
        };

        template<class... Args>
        using with = typename std::disjunction<is_constructible_x<Ts, Args...>...,
                                               fallback>::type;
    };

    // OK ，不实例化 is_constructible<Foo, double>
    static_assert(std::is_same_v<first_constructible<std::string, int, Foo>::with<double>,
                                 int>);

    static_assert(std::is_same_v<first_constructible<std::string, int>::with<>, std::string>);
    static_assert(std::is_same_v<first_constructible<std::string, int>::with<const char*>,
                                 std::string>);
    static_assert(std::is_same_v<first_constructible<std::string, int>::with<void*>, void>);

    int main() { }

### 参阅

negation (C++17) | 逻辑非元函数 (类模板)
conjunction (C++17) | 变参的逻辑与元函数 (类模板)