hax_xxx その2


関連:has_xxx
decltype を使わなくても一応、出来るみたいなのでやってみました。

// T::value が特定できない場合は、 false ではなくコンパイルエラーに・・・
/*
template<typename T>
struct has_value{
    typedef char yes;
    typedef struct{ char c[2]; } no;
    
    template<typename U>
    static yes check(U*, int U::* = &T::value);

    template<typename U>
    static no check(...);
    
    static const bool value = sizeof( check<T>(NULL) ) == sizeof(yes);
};
*/

template<typename T, int T::*>
struct sfinae_helper{
    typedef void type;
};

template<typename T, typename U = void>
struct has_value{
    static const bool value = false;
};

template<typename T>
struct has_value<T, typename sfinae_helper<T, &T::value>::type>{
    static const bool value = true;
};

struct hoge{
    int value;
};

struct foo{};

BOOST_STATIC_ASSERT(( has_value<hoge>::value ));   // ok
BOOST_STATIC_ASSERT(( has_value<foo>::value ));    // error


template の特殊化を使用すれば出来ました。
オーバーロードの方は、value が存在しないと『T::value が見つからない』とコンパイルエラーが…。


あと変数の型を指定しなければいけないので、ちょっとめんどくさいです。

struct hoge{
    float value;
};

struct foo{};

BOOST_STATIC_ASSERT(( has_value<hoge>::value )); // error : value は、float 型なので特定できない
BOOST_STATIC_ASSERT(( has_value<foo>::value ));  // error


vc8.0、vc9.0、vc10.0、gcc4.5.0 と手元にあるコンパイラで一通り試してみましたが問題なく動作してるみたいです。
bjam だと一括でコンパイル出来るのですごく便利。


ちなみにメンバ関数の場合は、こんな感じになります。

template<typename T, void (T::*)()>
struct sfinae_helper{
    typedef void type;
};

template<typename T, typename U = void>
struct has_func{
    static const bool value = false;
};

template<typename T>
struct has_func<T, typename sfinae_helper<T, &T::func>::type>{
    static const bool value = true;
};

struct hoge{
    void func();
};

struct foo{};

BOOST_STATIC_ASSERT(( has_func<hoge>::value ));   // ok
BOOST_STATIC_ASSERT(( has_func<foo>::value ));    // error


こっちも関数の型を指定しないとダメなので、やっぱりめんどくさいです。


[参照]
http://cpplover.blogspot.com/2008/10/hasxxx.html