C++1z(C++17)標準ライブラリで追加されるstd::conjunction
, std::disjunction
メタ関数では、型特性(type traits)のテンプレートインスタンス化が短絡評価(short-circuiting)される。&&
演算子, ||
演算子では左辺の真偽値によらず全項のインスタンス化が行われてしまうため、テンプレートメタプログラミングの文脈ではconjunction
, disjunction
メタ関数の方が使い勝手が良い。
- conjunctionメタ関数:型特性に対する論理積(AND); 短絡評価
- disjunctionメタ関数:型特性に対する論理和(OR); 短絡評価
- negationメタ関数:型特性に対する論理否定(NOT)
T
型が「std::atomic<T>
が常にロックフリー(lock free)か否か」を判定するメタ関数は、std::conjunction
メタ関数を利用して下記の通りに記述できる。*1
// C++1z(C++17) #include <atomic> #include <type_traits> template <typename T> struct is_lock_free_impl : std::bool_constant<std::atomic<T>::is_always_lock_free> { }; template <typename T> using is_lock_free = std::conjunction<std::is_trivially_copyable<T>, is_lock_free_impl<T>>; // ★
メタ関数is_lock_free
の定義で&&
演算子を使った場合、左辺std::is_trivially_copyable<T>::value
の真偽値に関わらず右辺is_lock_free_impl<T>::value
のインスタンス化が行われる。std::atomic<T>
はクラステンプレートの要件として Trivially Copyable な型を要求するため*2、下記コードではメタ関数is_lock_free_impl
インスタンス化の過程でコンパイルエラーとなってしまう。
template <typename T> struct is_lock_free : std::bool_constant< std::is_trivially_copyable<T>::value && is_lock_free_impl<T>::value // ★ &&演算子 > { }; // (std::atomic<int>型がロックフリーに振る舞う処理系を仮定) static_assert( is_lock_free<int>::value, "int is lock-free" ); // OK // 非Trivially Copyableなクラス型X struct X { ~X() {} }; static_assert( !is_lock_free<X>::value, "X is not lock-free" ); // NG: ill-formed
N4659(C++1z DIS) 23.15.8/p2-3, p7-8より引用。
template<class... B> struct conjunction : see below { };
2 The class templateconjunction
forms the logical conjunction of its template type arguments.
3 For a specializationconjunction<B1, ..., BN>
, if there is a template type argumentBi
for whichbool(Bi::value)
isfalse
, then instantiatingconjunction<B1, ..., BN>::value
does not require the instantiation ofBj::value
forj > i
. [Note: This is analogous to the short-circuiting behavior of the built-in operator&&
. --end note]
template<class... B> struct disjunction : see below { };
7 The class templatedisjunction
forms the logical disjunction of its template type arguments.
8 For a specializationdisjunction<B1, ..., BN>
, if there is a template type argumentBi
for whichbool(Bi::value)
istrue
, then instantiatingdisjunction<B1, ..., BN>::value
does not require the instantiation ofBj::value
forj > i
. [Note: This is analogous to the short-circuiting behavior of the built-in operator||
. --end note]
関連URL
- P0013R1 Logical Operator Type Traits (revision 1)
- c++ - How to use std::atomic<T>::is_always_lock_free for SFINAE? - Stack Overflow
- cppreference: std::conjunction, std::disjunction
- static_assert+標準メタ関数 - yohhoyの日記
*1:std::bool_constant, std::is_always_lock_free はいずれもC++1z標準ライブラリで追加される。
*2:N4659 32.6/p1: "The template argument for T shall be trivially copyable."