2011-03-14

Boost.Type Traitsへの拡張案のレビュー開始

Boost.Type Traitsへの拡張案のレビューが始まっている。これは、has_operator_XXXという一連のメタ関数を付け加えるものである。オペランドの型同士で、演算子をサポートしていれば、trueを返すメタ関数である。

これは、希望的には、以下の様なことをしてほしい。

struct X { } ;
int operator + (int, X) ;

int main()
{
    using namespace boost ;
    has_operator_plus<int, int>::value ; // true
    has_operator_plus<X, int>::value ; // false
    has_operator_plus<int, X>::value ; // Boostの実装では動かない。true, 演算子のオーバーロード
    has_operator_plus<X *, int>::value ; // true, ポインターと整数型の演算
}

ところが、現状の実装では、ここまで柔軟に動いてはくれない。なぜならば、decltypeを使っていないからだ。できるのは、オペランドの方がポインター型や基本型だった場合の、演算適用性の可否である。

ちなみに、decltypeを使えば、正しくジェネリックに動くメタ関数は簡単に書ける。例えば、以下のようになる。

template < typename T1, typename T2 >
struct has_operator_plus_impl
{
private :
    template < typename U1, typename U2 >
    static auto check( U1 u1, U2 u2 ) -> decltype( u1 + u2, std::true_type() ) ;
    template < typename ... Types >
    static std::false_type check( Types ... ) ;
public :
    static const bool value = decltype( check( std::declval<T1>(), std::declval<T2>() ) )::value ;
} ;

template < typename T1, typename T2 >
struct has_operator_plus
    : std::integral_constant< bool, has_operator_plus_impl< T1, T2 >::value >
{ } ;

ただし、このコードが正しく動くコンパイラーは、まだ存在しない。なぜならば、どのコンパイラーも、decltypeを正しく実装していないからだ。workaroundとしては、decltypeを以下のコードように変更すると、gccで動く。

std::common_type< decltype( check( std::declval<T1>(), std::declval<T2>() ) ) >::type::value

結局、Boostが未だにdecltypeを積極的に使わないのは、まだ正しく実装したコンパイラーが存在しないからだろう。

No comments: