mbind(std::bindのメタ関数版)

std::bind は<functional>ヘッダにあるC++11の標準ライブラリで、関数やラムダ式など operator() で呼び出すことが可能なオブジェクト(Callable)に対し、引数を部分的に束縛(bind)するものだ。「呼び出し」とは実行時の関数呼び出しのことであり、引数は値である。
ここで説明する mymd::mbind はそれと同じようなことをメタ関数などのテンプレートテンプレート名に対して行うもので、型を引数に取りコンパイル時に評価される式である。

class template: mymd::mbind

namespace mymd {
    // mbindの主要インタフェース(他のメンバーは省略)
    template <template <typename...> class M, typename... binder>
    class mbind {
    public:
        template <typename... V>
            using apply = プレースホルダに型を代入してできる型;
    };
}

概要

クラステンプレート M に対し、引数を部分的に束縛(bind)する。
apply<型...> で残りの引数型を指定する。

テンプレート引数

  • M -- 複数の型を引数に取るクラステンプレート
  • binder... -- 束縛対象の型もしくはプレースホルダ(_x_, _xrr_, _xrcv_ 等)

メンバーテンプレート

  • apply -- apply<型...> としたとき型を表す式となる。ここに指定できる型の数は、mbind のテンプレート引数に指定したプレースホルダの数に等しい。すべて通常の型であった場合は M<...> の型。ひとつ以上のプレースホルダを再度指定した場合は mbind 型である。

メタ関数の例として<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>;と定義されている。

論理 or、論理 and、論理 not

mbind そのものはインスタンスを作る意味はあまりないが、インスタンスに対する operator ||, operator &&, operator ! が定義されているので、論理 or、論理 and、論理 notを作るときはインスタンス化するとやりやすい。これを型に対する式で表そうとすると相当ややこしくなってしまう。(サンプル参照)

モジュール

hppファイル: miscellaneous/mbind.hpp at master · mYmd/miscellaneous · GitHub
サンプル: miscellaneous/test_mbind.cpp at master · mYmd/miscellaneous · GitHub
[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ http://melpon.org/wandbox/permlink/6GFinX4byC5j6bCZ