yohhoyの日記

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

static_assert+標準メタ関数

C++11 static_assert条件部の定数式(constant expression)にて、標準ライブラリ提供のメタ関数を利用するときのメモ。

2017-11-10追記:一部のメタ関数で意図しないコンパイルエラーを引き起こすため、このイディオムを使うべきでない。C++1z(C++17)標準ライブラリで追加される変数テンプレート版メタ関数(std::is_same_v<T,U>など)利用を推奨する。詳細は id:yohhoy:20171110 参照。

標準ヘッダ type_traits が提供するメタ関数を使うとき、下記2通りのいずれかで記述できる。後者の方が見やすい?

#include <type_traits>

// is_sameメタ関数の利用例
static_assert( std::is_same<int, int>::value, "1" );  // OK
static_assert( std::is_same<int, int>{}, "2" );       // OK

これらのメタ関数は、必ずstd::true_typeまたはstd::false_typeから派生、つまりstd::integral_constant<bool, v>からの公開派生クラスとなる。クラステンプレートintegral_constantは「constexpr静的bool型定数メンバvalue」と「constexprなbool型への変換演算子」をもっているため、定数式が要求される場所では例示コードの記述が可能。N3337 20.9.3より引用(コードは簡略化している)。

namespace std {
  template <class T, T v>
  struct integral_constant {
    static constexpr T value = v;
    constexpr operator T() { return value; }
  };
  typedef integral_constant<bool, true> true_type;
  typedef integral_constant<bool, false> false_type;
}

メモ:クラスintegral_constantは条件を満たすためリテラル型(literal type)となる(3.9/p10)。{}は同リテラル型に対するlist-initializationとなるため(8.5.4/p1)、integral_constant<〜>{}は同クラス型のリテラル定数式(literal constant expression)として扱われる(5.19/p3)。このリテラル定数式に対してbool型への変換*1が働くことでconverted constant expressionとなり、これはliteral constant expressionでもあるため、最終的にbool型の定数式(constant expression)が得られる(5.19/p3)。おそらくは。

関連URL

*1:ここでは "contextually converted to bool" が行われる。→id:yohhoy:20121110