has_xxx
template< typename T > struct has_hoge{ typedef char yes; typedef struct{ char c[2]; } no; template<typename T> static yes check(T*, typename T::hoge* = 0); template<typename T> static no check(...); static const bool value = sizeof( check<T>(NULL) ) == sizeof(yes); }; struct test0{}; struct test1{ typedef int hoge; }; struct test2{ struct hoge{}; }; BOOST_STATIC_ASSERT(( has_hoge<test0>::value )); // error BOOST_STATIC_ASSERT(( has_hoge<test1>::value )); // ok BOOST_STATIC_ASSERT(( has_hoge<test2>::value )); // ok
has_xxx とは、クラス型に対して、特定の型名(typedef した型やインナークラス等)を持っているかどうかを判断する際に使われるテクニックです。
boost では、BOOST_MPL_HAS_XXX_TRAIT_DEF() マクロ関数を使用すれば簡単に実装を行う事が出来ます。
#include <boost/mpl/has_xxx.hpp> BOOST_MPL_HAS_XXX_TRAIT_DEF(hoge) struct test0{}; struct test1{ typedef int hoge; }; struct test2{ struct hoge{}; }; BOOST_STATIC_ASSERT(( has_hoge<test0>::value )); // error BOOST_STATIC_ASSERT(( has_hoge<test1>::value )); // ok BOOST_STATIC_ASSERT(( has_hoge<test2>::value )); // ok
しかし、この場合は、メソッド名やメンバ変数名を特定することは出来ません。
(例えば、begin() や end() のメソッドを持っているかどうかの判定をしたりとかは出来ない)
struct test3{ void hoge(); }; struct test4{ int hoge; }; BOOST_STATIC_ASSERT(( has_hoge<test3>::value )); // error BOOST_STATIC_ASSERT(( has_hoge<test4>::value )); // error
一応、これも C++0x の decltype を使えば、実装する事が出来ます。
template< typename T > struct has_hoge{ typedef char yes; typedef struct{ char c[2]; } no; template<typename T> static yes check(T*, typename T::hoge* = 0); // こいつを追加 template<typename T> static yes check(T* p, decltype(p->hoge)* = NULL); template<typename T> static no check(...); static const bool value = sizeof( check<T>(NULL) ) == sizeof(yes); }; struct test0{}; struct test1{ typedef int hoge; }; struct test2{ struct hoge{}; }; struct test3{ void hoge(); }; struct test4{ int hoge; }; BOOST_STATIC_ASSERT(( has_hoge<test0>::value )); // error BOOST_STATIC_ASSERT(( has_hoge<test1>::value )); // ok BOOST_STATIC_ASSERT(( has_hoge<test2>::value )); // ok BOOST_STATIC_ASSERT(( has_hoge<test3>::value )); // ok BOOST_STATIC_ASSERT(( has_hoge<test4>::value )); // ok
VC10だとこれで問題なく動いているけども大丈夫かな…。
decltype を使わないやり方は思いつかないや。
[参照]
http://cpplover.blogspot.com/2008/10/hasxxx.html
http://cpplover.blogspot.com/2010/01/c0x_23.html
http://www.boost.org/doc/libs/1_36_0/libs/mpl/doc/refmanual/has-xxx-trait-def.html