メンバ関数が存在するかをチェックするメタ関数

はじめまして
プログラマーの松延です。

今日はプログラムの話をしていこうと思います。
みなさんはあるクラスに特定のメンバ関数が存在するかどうかを調べるメタ関数が欲しいと思ったことはないですか?
既出感はありますが、そんな時に使えるメタ関数を作るマクロについて紹介しようと思います。

#define HAS_METHOD(func_name)
template<class ClassType> struct has_method_##func_name
{
    static auto check(...) -> decltype(std::false_type());

    template<typename _ClassType>
    static auto check(_ClassType&) ->
        decltype(static_cast<decltype(_ClassType::func_name)*>(&_ClassType::func_name), std::true_type());

    enum : bool { value =  decltype(check(std::declval<ClassType&>()))::value };
}

*上記コードはマクロの改行文字は省略してあります。

上記のマクロを

HAS_METHOD(HogeFunc);

int main()
{
    std::cout << has_method_HogeFunc<Hoge>::value << std::endl;
    return 0;
}

と使用するとクラス Hoge が HogeFuncメンバ関数 を持っているかを調べることができます。

ポイントは

static auto check(_ClassType&) ->
    decltype(static_cast<decltype(_ClassType::func_name)*>(&_ClassType::func_name), std::true_type());

です。

この行では_ClassTypeの持つfunc_nameメンバ関数を同じ型のメンバ関数ポインタにキャストしています。
キャストに成功した場合 operator, が std::true_type を返し、キャストに失敗した場合SFINAEの効果で

static auto check(...) -> decltype(std::false_type());

が使用され std::false_type が返されます。

マクロを使用したのは正直不本意でしたが

static_cast<decltype(_ClassType::func_name)*>(&_ClassType::func_name)

この部分に外部からfunc_nameを指定する方法が思いつかなかったためこのような形になりました。
ないとは思いますが operator をオーバーライドしている場合正しい結果を得られなくなる事があります。

ちなみにこのコードはC++11が使用できるコンパイラでないとビルドが通らないのでご注意を。

Follow me!