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, "");
も通ってしまいますが、差し当たって問題はない…かな?