yohhoyの日記

技術的メモをしていきたい日記

コンセプトと短絡評価

C++2a(C++20)コンセプトの制約式(constraint-expression)では、論理演算&&, ||は短絡評価される。*1

C++17現在のテンプレートメタプログラミングではstd::conjunction, std::disjunctionメタ関数を必要とするが、C++2aコンセプト導入により自然な制約記述が可能となる。

T型が「std::atomic<T>が常にロックフリー(lock free)か否か」を判定するメタ関数は、std::conjunctionメタ関数を利用して下記の通りに記述できる。

// 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インスタンス化が行われる。

conjunction/disjunctionと短絡インスタンス化
// C++2a
#include <atomic>
#include <type_traits>

// コンセプトis_lock_free
template <typename T>
concept is_lock_free
  = std::is_trivially_copyable_v<T> && std::atomic<T>::is_always_lock_free;

// (std::atomic<int>型がロックフリーに振る舞う処理系を仮定)
static_assert( is_lock_free<int>, "int is lock-free" );  // OK

// 非Trivially Copyableなクラス型X
struct X { ~X() {} };
static_assert( !is_lock_free<X>, "X is not lock-free" );  // OK

C++2a DIS(N4681) 13.5.1.1/p1-3より引用(下線部は強調)。

1 There are two binary logical operations on constraints: conjunction and disjunction. [Note: These logical operations have no corresponding C++ syntax. For the purpose of exposition, conjunction is spelled using the symbol ∧ and disjunction is spelled using the symbol ∨. The operands of these operations are called the left and right operands. In the constraint AB, A is the left operand, and B is the right operand. --end note]
2 A conjunction is a constraint taking two operands. To determine if a conjunction is satisfied, the satisfaction of the first operand is checked. If that is not satisfied, the conjunction is not satisfied. Otherwise, the conjunction is satisfied if and only if the second operand is satisfied.
3 A disjunction is a constraint taking two operands. To determine if a disjunction is satisfied, the satisfaction of the first operand is checked. If that is satisfied, the disjunction is satisfied. Otherwise, the disjunction is satisfied if and only if the second operand is satisfied.

関連URL

*1:C++コンセプト制約式を用いたオーバーロード解決においては、演算子 &&, ||, ! がブール代数的な論理積論理和/論理否定から期待されるセマンティクスとは多少異なる動作をする。詳細は C++コンセプトとド・モルガンの法則 を参照のこと。