2012-06-09

ある関数/メンバー関数がある型の仮引数をもっているかどうかを判定するメタプログラム

そういえば最近、メタプログラムを書いていないので、書いてみることにした。ある関数、もしくはメンバー関数が、ある型の仮引数を持っているかどうかを調べるメタプログラムだ。

template < std::size_t I, typename T, typename TUPLE >
struct has_parameter_type_impl
{
    using type = std::integral_constant< bool,
        std::is_same<T, typename std::tuple_element< I, TUPLE >::type >::value
        || has_parameter_type_impl< I-1, T, TUPLE>::type::value
    > ;
} ;

template < typename T, typename TUPLE>
struct has_parameter_type_impl< 0, T, TUPLE >
{
    using type = std::integral_constant< bool,
        std::is_same<T, typename std::tuple_element< 0, TUPLE >::type >::value
    > ;
} ;

template < typename T, typename Func >
struct has_parameter_type
{ } ;

template < bool B, typename T, typename F >
struct lazy_conditional
    : std::conditional< B, T, F >::type
{ } ;

template < typename T, typename R, typename ... Types >
struct has_parameter_type<T, R (Types...) >
    : lazy_conditional< sizeof...(Types) == 0
        , std::conditional< std::is_same<T, void>::value, std::true_type, std::false_type >
        , has_parameter_type_impl< sizeof...(Types) - 1, T, std::tuple< Types... > >
        >::type
{ } ;



template < typename T, typename R, typename ... Types >
constexpr bool has_param_type( R && ( Types ... ) )
{
    return has_parameter_type<T, R( Types... )>::value ;
}

template < typename T, typename R, typename ... Types >
constexpr bool has_param_type( R (*) ( Types ... ) )
{
    return has_parameter_type<T, R( Types... )>::value ;
}

template < typename T, typename R, typename C, typename ... Types >
constexpr bool has_param_type( R (C::*) ( Types ... ) )
{
    return has_parameter_type<T, R( Types... )>::value ;
}

使い方

struct X
{

    void f( char, double ) { }
} ;

void f( int, char, short ) { }

int main()
{
    std::cout << has_param_type<int>( &f ) << std::endl ; // true
    std::cout << has_param_type<float>( &f ) << std::endl ; // false
    std::cout << has_param_type<double>( &X::f ) << std::endl ; // true
}

残念ながら、メンバー関数をコンパイル時にイテレートする方法がないので、クラス型を与えただけで自動的にメンバー関数を総なめにして判別してくれるメタプログラムは書けない。

N3326: Sequential access to data members and base sub-objectsをメンバー関数にも適用した機能が待ち望まれる。

No comments: