定数と型で処理を変えたい

定数だった場合に、boost::integral_constant でラップして返すようなメタ関数が欲しかったのでやってみました。

#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/utility/enable_if.hpp>
 
#include <boost/mpl/bool.hpp>
#include <boost/mpl/identity.hpp>

namespace mpl = boost::mpl;

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

template<typename T, typename U = void>
struct is_constant_value : mpl::false_{};

template<typename T>
struct is_constant_value<T, typename sfinae_helper<T>::type> : mpl::true_{};

template<typename T, typename U = void>
struct element_value : mpl::identity<typename T::value>{};

template<typename T>
struct element_value<T, typename boost::enable_if<is_constant_value<T> >::type>
    : boost::integral_constant<int, T::value>{};


struct hoge{
    static int const value = 10;
};
struct hoge2{
    typedef boost::integral_constant<int, 3>::type value;
};

BOOST_STATIC_ASSERT((
    element_value<hoge>::type::value == 10
));

BOOST_STATIC_ASSERT((
    element_value<hoge2>::type::value == 3
));


int main(){}


これ以上スマートな方法は思いつかなかった!
is_constant_value が決め打ちなのでちょっと汎用性に欠けますが仕方がないかなぁ……。

ざん☆がい

namespace detail{

typedef struct{ char a[2]; } yes_type;
typedef struct{ char a[1]; } no_type;

template<int N>
yes_type
is_constant_check();

template<typename T>
no_type
is_constant_check();

}

#define IS_CONSTANT(_src) \
	boost::mpl::bool_<sizeof(detail::is_constant_check<_src>()) == sizeof(detail::yes_type)>

BOOST_STATIC_ASSERT(( IS_CONSTANT(3)::value ));
BOOST_STATIC_ASSERT(( IS_CONSTANT(int)::value == false ));


最初はこんな感じの、is_constant で切り替えようとしていたんですが色々と弊害があったのでやめました。
単体で使う分にはいいんですが、template 型の場合、typename を付けないとダメだったり使い物になりませんでした。
んー難しいなぁ……。

IS_CONSTANT(T::value); // T::value が型だった場合は、typename を付けないとエラー


[boost]
ver 1.45.0