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