2008-09-19

TR1のrefの実装が難しい

ふと、TR1のrefを実装しようと思い立った。それほど面倒になるとは思わなかったのだが、恐ろしく難儀している。一体このライブラリは設計した奴は変態ではなかろうか。誰にせよ、メタプログラムを呼吸している奴に違いない。かなり難しい。

普通に部分的特殊化だけで場合分けして実装していると、同じようなコードの重複が目立ってきたので、CRTPを使うことにした。これなら簡潔に記述できる。

ところで、行き詰ったところがある。ネストされた型名、unary_functionやbinary_functionを継承しているかどうか判別するメタ関数の書き方は分かる。result_typeがあるかどうかを判別するメタ関数の書き方も分かる。しかし、以下のコードはコンパイルが通るべきなのだろうか。

#include <functional>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
struct Foo
    : std::unary_function<int, void>
    , std::binary_function<int, int, void>
{
    typedef void result_type ;
    void operator () (int x) const
    { }

    void operator () (int x, int y) const
    { }
} ;

template < typename T >
void check( T x )
{
    BOOST_STATIC_ASSERT(( boost::is_base_of< std::unary_function<int, void>, T >::value )) ;
    BOOST_STATIC_ASSERT(( boost::is_base_of< std::binary_function<int, int, void>, T >::value )) ;   
}

int main()
{
    check( std::tr1::cref( Foo() ) ) ;
}

ご存知のとおり、C++には、オーバーロードと多重継承がある。したがって、クラスFooはunary_functionでもあり、binary_functionでもある。ドラフト規格では、このコードがコンパイルエラーになるべきだとは言っていない。するとこのコードはコンパイルできるべきなのだろうか。しかし、もしコンパイル可能であるべきならば、reference_wrapperでも多重継承を使わなければならない。EBCOの観点から見て、あまり好ましくないと思うのだが。

ちなみに、DinkumwareのTR1の実装は、このコードをコンパイルできない。

No comments: