2008-08-18

コンセプトはとても厳格である。

コンセプトは、型にたいする要求をする機能だ。「俺はこの型にたいしてかくかくしかじかの操作をする。そのほかのとらとらうまうまな操作は絶対しない。安心しろ」と公言する機能である。しかし、とても厳格だ。

例えば、二つの引数を足して返す、簡単な関数テンプレートを実装したいとしよう。C++03を話すことのできる者ならば、簡単に書くことができる。

template < typename T > requires Addable< T >
T add( T const & x, T const & y )
{
    return x + y ;
}

これ以上に無いくらい簡単だ。必要なのは、コンセプトAddableを書くだけだ。どのように書けばいいのだろう。コンセプトの初心者は、次のように書くことだろう。

auto concept Addable < typename T >
{
    T operator + ( T const &, T const & ) ;
}

しかしこのコードはコンパイルエラーになる。一体何が悪いというのか。それはadd関数が値を返しているからだ。値を返すには、コピーコンストラクタがなければならない。然るによって、コピーコンストラクタを明記してやらねばならない。一体何故コピーコンストラクタのようなトリビアルなものですら要求しなければならないのかといぶかる人がいるかもしれないが、すべての操作を要求しなければならないのだから、しかたがない。

auto concept Addable < typename T >
{
    T::T( T const & ) ;
    T operator + ( T const &, T const & ) ;
}

しかしもし、add関数を次のように書いたならば、このコンセプトはエラーになる。

template < typename T > requires Addable< T >
T add( T const & x, T const & y )
{
    T temp ;
    temp = x + y ;
    return temp ;
}

なぜならば、T型の変数を、初期化せずに宣言したということは、デフォルトコンストラクタがなければならないからだ。また、代入演算子も使っているので、それも要求しなければならない。代入演算子と、new, new[], delete, delete[]だけは、メンバ関数として要求する必要がある。

auto concept Addable < typename T >
{
    T::T( ) ;
    T::T( T const & ) ;
    T T::operator = ( T const & ) ;
    T operator + ( T const &, T const & ) ;
}

これはとても面倒くさい。そこで、標準ライブラリとして、あらかじめよく使いそうなコンセプトを定義してある。

namespace std {

auto concept CopyConstructible< typename T >
{
    T::T( const T & ) ;
}

auto concept DefaultConstructible< typename T >
{
    T::T( ) ;
}

auto concept CopyAssignable< typename T, typename U = T >
{
    typename result_type;
    result_type T::operator = ( U const& ) ;
}

}// namespace std

これを使えば、上記のコードは次のように書ける。

auto concept Addable < typename T >
{
    requires std::DefaultConstructible< T > ;
    requires std::CopyConstructible< T > ;
    requires std::CopyAssignable< T > ;
    T operator + ( T const &, T const & ) ;
}

std::Assignableは、ConceptGCC 4.3.0 Alpha 7のconceptsでは定義されていなかった。

なお、実はstd::Addableというのもある。ただしこれはoperator +とresult_typeだけのコンセプトなので、注意されたし。

ともかく、コンセプトを使うには、クラスやテンプレートに関してとてもとても詳しくなければならない。

No comments: