yohhoyの日記

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

真偽値を返すメタ関数利用上の注意

C++標準ライブラリ <type_traits> ヘッダ提供の真偽値を返すメタ関数において、is_xxx<T>{}のような真偽値変換(→id:yohhoy:20121207)は適切でないケースがある。素直にis_xxx<T>::valueで真偽値を取り出すか、C++1z(C++17)で追加される変数テンプレート版メタ関数is_xxx_v<T>の利用が望ましい。

C++1z標準ライブラリconjunction, disjunctionメタ関数ではインスタンス化の短絡評価をサポートするが、is_xxx<T>{}方式では期待通りに短絡評価が機能しなくなる。例示として id:yohhoy:20171103 サンプルコードを引用。

// 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>>;

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

is_lock_free<X>{}std::conjunction<B...>型のインスタンス化を要求するため、本来は短絡評価でスキップされるべきis_lock_free_impl<X>型のインスタンス化を要求してしまい、ill-formedによる意図しないコンパイルエラーを引き起こす。

ノートconjunction, disjunctionメタ関数を直接公開(alias template)せず、std::bool_constantでラップすれば問題を回避することは一応可能。

template <typename T>
struct is_lock_free
  : std::bool_constant<
      std::conjunction_v<std::is_trivially_copyable<T>, is_lock_free_impl<T>>
    > { };

static_assert( !is_lock_free<X>::value, "X is not lock-free" );  // OK
static_assert( !is_lock_free<X>{},      "X is not lock-free" );  // OK