2011-03-01

C++0xとC++03の比較

2ch.netのC++0xスレのために書いたコードを、試しに、C++03に移植してみた。

まずは、C++0x版から。

#include <iostream>
#include <vector>

// range_traits案の実装
namespace std
{
 
template<class T>
struct range_traits
{
    static auto begin( T & t ) -> decltype( t.begin() ) { return t.begin() ; }
    static auto end( T & t ) -> decltype( t.end() ) { return t.end() ; }
    static auto begin( T const & t ) -> decltype( t.begin() ) { return t.begin() ; }
    static auto end( T const & t ) -> decltype( t.end() ) { return t.end() ; }
} ;
 
}
 
// 使用方法
template < typename Container >
void print( Container && c )
{
    using traits = std::range_traits< typename std::decay< Container >::type > ;
    for ( auto iter = traits::begin( c ), end = traits::end( c ) ; iter != end ; ++iter )
    { std::cout << *iter << std::endl ; }
}
 
int main()
{
    std::vector< int > v = { 1, 2, 3, 4, 5 } ;
    print( v ) ;
}

このコードは、なかなか簡潔だ。しかもすばらしくジェネリックである。

C++03は非常に劣った言語で、autoもdecltypeもrvalueリファレンスも新しい関数記法もエイリアス宣言も初期化リストもない。となると、上記のコードは、大幅に書きなおさなければならない。

#include <iostream>
#include <vector>

// range_traitsの実装
namespace std
{
 
template<class T>
struct range_traits
{
    static typename T::iterator begin( T & t ) { return t.begin() ; }
    static typename T::iterator end( T & t ) { return t.end() ; }
    static typename T::const_iterator begin( T const & t ) { return t.begin() ; }
    static typename T::const_iterator end( T const & t ) { return t.end() ; }
} ;
 
}
 
// 使用方法
template < typename Container >
void print( Container const & c )
{
    typedef std::range_traits< Container > traits ;
    typedef typename Container::const_iterator iterator ;
    for ( iterator iter = traits::begin( c ), end = traits::end( c ) ; iter != end ; ++iter )
    { std::cout << *iter << std::endl ; }
}
 
int main()
{
    std::vector< int > v ;
    v.push_back( 1 ) ;
    v.push_back( 2 ) ; 
    v.push_back( 3 ) ;
    v.push_back( 4 ) ;
    v.push_back( 5 ) ;

    print( v ) ;
}

だいぶ、ジェネリック度が下がっている。それに、この場合はconstなlvalueリファレンスでもいいのだが、何かもっと大胆なことをしようとすると、やはりrvalueリファレンスが欲しいところだ。typedef指定子の文法は分かりづらい。

ちなみに、range-based forのために、range_traitsが採用されることは、まず確実にないと考えている。かなり意見が割れているので、規格の制定を遅らせないために、もしかしたら、現状維持かもしれない。しかし、やはりADLに頼るのはやめてほしいのだが。

No comments: