C++11 で has_method を書いてみた

C++03 だと Boost.TTI とかがあるんですが、C++11 でも書いてみました。
テンプレート引数で decltype(&T::method) を使用するとオーバーロード等で複数の名前の関数がある場合に特定に失敗するので今回は decltype で直接関数呼び出しを行って SFINAE しています。

[ソース]

#include <type_traits>


template<typename T, typename ...Args>
auto
has_method_impl(int)
->decltype(std::declval<T>().method(std::declval<Args>()...), std::true_type{});

template<typename T, typename ...Args>
std::false_type
has_method_impl(...);

template<typename T>
struct has_method;

template<typename T, typename ...Args>
struct has_method<T(Args...)> : decltype(has_method_impl<T, Args...>(0)){};


struct non_const_method{
    void method(){}
};

struct const_method{
    void method() const{}
};

struct X{
    void method(){}
    void method(int) const{}
    void method(float, float){}
};


int
main(){
    static_assert( has_method<non_const_method()>::value, "");
    static_assert(!has_method<non_const_method const()>::value, "");

    static_assert( has_method<const_method()>::value, "");
    static_assert( has_method<const_method const()>::value, "");

    static_assert( has_method<X()>::value, "");
    static_assert(!has_method<X const()>::value, "");
    static_assert( has_method<X const(int)>::value, "");
    static_assert( has_method<X const(float)>::value, "");
    static_assert( has_method<X      (float, float)>::value, "");
    static_assert(!has_method<X const(float, float)>::value, "");
    static_assert(!has_method<X const(int, int, int)>::value, "");

    return 0;
}

流石に C++11 だとだいぶすっきりしている実装になっていますね。
decltype を使用して関数の呼び出しを行なっているので

static_assert(has_method<X const(float)>::value, "");

も通ってしまいますが、差し当たって問題はない…かな?


[コンパイラ]

  • g++ (GCC) 4.7.0 20120218 (experimental)
  • clang++ (LLVM) 3.1 20120226(trunk)