C++11ではエイリアステンプレートという便利なものが使うことができます。
template < class Ty1, class Ty2 = void >
using enable_if = std::enable_if < Ty1::value, Ty2 >;
すばらしい。これを使うと新たな構造体を作ることなく新たな発展形を作ることができます。
まずはヘルパ構造体をつくる。
std::true_typeとは反対のものです。いい名前が思い浮かばない。
template < bool > // convert from bool_value to bool_type
struct meta_bool : std::true_type {};
template <>
struct meta_bool< false > : std::false_type{};
trueやfalseからstd::true_typeやstd::false_typeを生成することが出来ます。
std::integral_constantから直接生成してもいいのですけれど。
まずは、論理反転です。
template < class Ty >
using meta_not = meta_bool < !Ty::value >;
エイリアステンプレートで作られたこのメタ関数は、抽象的な論理反転をします。
これは非常に便利なもので、type_traitsのメタ関数は基本的に値を受け取るものがほとんどです。
std::enable_if < true >
こんな感じですよね。
それを高階関数にするのはごく普通のことです。
std::enable_if < std::is_same < void, void >::value >::type
とするよりは、
template < class Ty1, class Ty2 = void >
using enable_if = std::enable_if < Ty1::value, Ty2 >;
というものを作り、
enable_if < std::is_same < void, void > >::type
とした方が圧倒的に分かりやすいのです。
しかしこうすると論理反転などの操作で困りますので、上記のメタ関数が訳に立ちます。
std::enable_if < !std::is_same < void, void >::value >::type
enable_if < meta_not < std::is_same < void, void > > >::type
うむ。
同じように、論理和とかとか。
//
// meta-or
template < class Ty, class... Args >
struct meta_or
: conditional_t < Ty, std::true_type, meta_or < Args... > >
{
};
template < class Ty >
struct meta_or < Ty >
: meta_bool < Ty::value >
{
};
conditional_tはさっきの高階関数の思想に基づいたstd::conditionalの拡張版です。
オリジナルのboost::conditionalはこっちだった気がするんだけどどうだったっけか……
//
// conditional
template < class _Test, class _Ty1, class _Ty2 >
using conditional = std::conditional < _Test::value, _Ty1, _Ty2 >;
template < class _Test, class _Ty1, class _Ty2 >
using conditional_t = typename conditional< _Test, _Ty1, _Ty2 >::type;
論理積は論理和と論理否定だけで作ることができます。
//
// meta-and
template < class... Args >
using meta_and = meta_or < meta_not < Args >... >;
A && B は !( !A || !B ) に等しいです。
わたしはなるべく継承よりエイリアステンプレートだけでメタ関数を書くようにしているのですが、
Visual Studio 2014 CTPではエイリアステンプレート周りにバグがあるようですね。
このmeta_andを書いた時、meta_not < Args >...
で引っかかったので頭を抱えたのですが、GCCで通りましたのでよくあるVSのバグだと判断しました。
バグじゃなくて未定義動作だよ!とかご存知のかたいらっしゃったらコメント頂けると嬉しいです。
VSをお使いの方は
//
// meta-not
template < class A >
struct meta_not
: meta_bool < !A::value >
{
};
こういうふうにした方が良いかもしれません。
他にも型操作周りにはバグが多く、VSにはこまったものですが、エディタがとても好きなのでやっぱりこまったものです。
少しだけ具体的な利用例を出しますね。
使用方法としては、SFINAEやコンセプトの条件などが主になると思います。
template < class Ty1, class Ty2 = void >
using enable_if_t = typename std::enable_if < Ty1::value, Ty2 >::type;
//
// 文字列だけを受け取るprint
template < class Ty,
enable_if_t < meta_or < std::is_same < Ty, char >, std::is_same < Ty, wchar_t > > >* = nullptr >
void print( const Ty* text );
こんなところでしょうか。
では、この辺で。