mbind はstd::bindと同じようなことをメタ関数などのテンプレートテンプレート名に対して行うもので、型を引数に取りコンパイル時に評価される式である。作って1年以上放置していたが、最近少し直したので記事にした。(Hatena Blogからの再掲です。)
class template: mymd::mbind
namespace mymd {
// mbindの主要インタフェース(他のメンバーは省略)
template <template <typename...> class M, typename... binder>
class mbind {
public:
template <typename... V>
using apply = 各プレースホルダにV...を代入してできる型;
};
}
概要
クラステンプレート M に対し、型引数を部分的に束縛(bind)する。
mbind<F, binder...> の binder... の中にプレースホルダ(_x_, _xrr_, _xrcv_ 等)が含まれていれば、その位置に apply<V...> を使って任意の型を代入することができる。
テンプレート引数
M -- 複数の型を引数に取るクラステンプレート
binder... -- 束縛対象の型もしくはプレースホルダ(_x_, _xrr_, _xrcv_ 等)の列
メンバーテンプレート
apply -- apply<V...> が型を定義する。V... に入れられる型の数は、mbind のテンプレート引数 binder... に含まれるプレースホルダの数に等しい。V... にプレースホルダが含まれていない場合は M<T...> になる(M<T...>::type ではない)。ここで T... は binder... の中のプレースホルダを順に V... の元に置き換えたものである。ひとつ以上のプレースホルダが V... に含まれている場合は mbind 型となり、続けて apply が可能となる。
例
メタ関数の例として<type_traits> の std::is_convertible をとる。
#include <type_traits>
using mymd::_x_;
using b = mymd::mbind<std::is_convertible, int, _x_>; // 第1引数をintに束縛する
static_assert(b::apply<double>::value, "not convertible!!"); // intからdoubleへの変換は可能
static_assert(!b::apply<int*>::value, "not convertible!!"); // intからint*への変換は不可能
次はtuple の例。
#include <tuple>
// 完成型は5要素のtuple
using tuple5 = std::tuple<char, std::string, int, char, int>;
using mymd::_x_;
// 3つの型を束縛(2つはプレースホルダ)
using bind_3_5 = mymd::mbind<std::tuple, char, _x_, int, _x_, int>;
// 残り2つの型を指定する
using bind_5_5 = bind_3_5::apply<std::string, char>;
static_assert(std::is_same<bind_5_5, tuple5>::value, "!=");
定義済みプレースホルダ
apply でプレースホルダに対して任意の型を代入したとき、プレースホルダの種類によって以下のように変換される。
mymd::_x_ -- 基本のプレースホルダ。型変換せずそのまま代入される。
mymd::_xrr_ -- std::remove_reference<型>::type が代入される。
mymd::_xrcv_ -- std::remove_cv<型>::type が代入される。
mymd::_xrcvr_ -- std::remove_cv<std::remove_reference<型>::type>::type が代入される。
mymd::_xdecay_ -- std::decay<型>::type が代入される。
これらはプレースホルダ生成型である mymd::_pX_ から定義されている。_pX_ にメタ関数の列 convert... を与えて _pX_<convert...> を作れば、型 T に対してconvert0<convert1<convert2<... <T>>...> が評価されるようになっている。たとえば _xrcvr_ は _pX_<std::remove_cv, std::remove_reference> と定義されている。
convert<T> か convert<T>::type かは勝手に判断している。(再考の余地あり?)
論理 or、論理 and、論理 not
mbind そのものはインスタンスを作る意味はあまりないが、インスタンスに対する operator ||, operator &&, operator ! が定義されているので、論理 or、論理 and、論理 notを作るときはインスタンス化するとやりやすい。これを型に対する式で表そうとすると相当ややこしくなってしまう。
モジュール
hppファイル: https://github.com/mYmd/miscellaneous/blob/master/mbind.hpp
サンプル: https://github.com/mYmd/miscellaneous/blob/master/test_mbind.cpp
[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ : http://melpon.org/wandbox/permlink/6GFinX4byC5j6bCZ