std::disjunction
| ヘッダ <type_traits> で定義 |
||
| template< class... B > struct disjunction; |
(C++17以降) | |
型特性 B... の論理和 (logical disjunction) を形成し、実質的に型特性のシーケンスに対して論理ORを実行します。
特殊化 std::disjunction<B1, ..., BN> は、以下の公開かつ明確な基底クラスを持ちます。
- sizeof...(B) == 0 の場合、std::false_type。それ以外の場合、
- bool(Bi::value) == true である、`B1, ..., BN` の最初の型 `Bi`。そのような型がない場合は `BN`。
基底クラスのメンバー名のうち、`disjunction` と `operator=` 以外のものは隠蔽されず、`disjunction` 内で明確に利用可能です。
disjunction はショートサーキット評価されます。bool(Bi::value) != false となるテンプレート型引数 `Bi` が存在する場合、disjunction<B1, ..., BN>::value のインスタンス化は、`j > i` の `Bj::value` のインスタンス化を必要としません。
プログラムが `std::disjunction` または `std::disjunction_v` の特殊化を追加した場合、動作は未定義です。
目次 |
[編集] テンプレートパラメータ
| B... | - | Bi::value がインスタンス化されるすべてのテンプレート引数 `Bi` は、基底クラスとして使用可能であり、bool に変換可能なメンバー `value` を定義する必要があります。 |
[編集] ヘルパー変数テンプレート
| template< class... B > 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 のいずれかから継承するわけではありません。それは、bool に明示的に変換された `::value` が true となる最初の `B` から、または、それらすべてが false に変換される場合は最後の `B` から単に継承します。例えば、std::disjunction<std::integral_constant<int, 2>, std::integral_constant<int, 4>>::value は 2 です。
ショートサーキットインスタンス化は、`disjunction` を畳み込み式 (fold expressions) と区別します。(... || Bs::value) のような畳み込み式は `Bs` 内のすべての `B` をインスタンス化するのに対し、std::disjunction_v<Bs...> は値が決定された時点でインスタンス化を停止します。これは、後の型が高価なインスタンス化を伴う場合や、誤った型でインスタンス化された場合にハードエラーを引き起こす可能性がある場合に特に役立ちます。
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_lib_logical_traits |
201510L |
(C++17) | 論理演算子型特性 |
[編集] 例
#include <cstdint> #include <string> #include <type_traits> // values_equal<a, b, T>::value is true if and only if 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 is always true template<typename T> struct default_type : std::true_type { using type = T; }; // Now we can use disjunction like a switch statement: 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> // must be last! >::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>); // checking if Foo is constructible from double will cause a hard error 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 to return if nothing is found }; template<class... Args> using with = typename std::disjunction<is_constructible_x<Ts, Args...>..., fallback>::type; }; // OK, is_constructible<Foo, double> not instantiated 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() {}
[編集] 関連項目
| (C++17) |
論理NOTメタ関数 (クラステンプレート) |
| (C++17) |
可変長論理ANDメタ関数 (クラステンプレート) |