n2581 Named Requirements for C++0X Concepts
n2780 Named Requirements for C++0X Concepts, version 2
私は、コンセプトを使うのは簡単であると、一度も言ったことがない。寝言で言ったかもしれないが、それは所詮寝言だ。たとえば、STLのsortに使えるイテレータを持ったrangeを扱う場合には、以下のように記述する必要がある。
template < typename T >
requires std::Range< T >
&& std::RandomAccessIterator< std::Range< T >::iterator >
&& std::ShuffleIterator< std::Range< T >::iterator >
&& std::LessThanComparable< std::Range< T >::iterator::value_type >
void f(T & r)
{
std::sort( begin(r), end(r) ) ;
}
もちろん、すべてをrequires-clauseに記述するのではなく、constrained-template-parameter(テンプレート引数のtypename/classの場所)にRangeを指定すれば、この重複を省くことができる。しかし、constrained-template-parameterで指定できるコンセプトはひとつだけなので、もっと複雑になると、こうなる。
template<InputIterator Iter1, InputIterator Iter2, typename T>
requires Multiplicable< Iter1::reference
, Iter2::reference
>
&& Addable< T
, Multiplicable< Iter1::reference
, Iter2::reference
>::result_type
>
&& Assignable< T
, Addable< T
, Multiplicable< Iter1::reference
, Iter2::reference
>::result_type
>::result_type
>
T inner_product( Iter1 first1, Iter1 last1, Iter2 first2, T init );
言うまでもなく、このコードは冗長にも程がある。そこで、named requirementが提案され、このたびドラフト規格に入った。これは文字通り名前をつける機能で、以下のようになる。
template<InputIterator Iter1, InputIterator Iter2, typename T>
requires mult = Multiplicable<Iter1::reference, Iter2:reference>
&& add = Addable<T, mult::result_type>
&& Assignable<T, add::result_type>
T inner_product( Iter1 first1, Iter1 last1, Iter2 first2, T init );
とても分かりやすい。
これはrequires-clauseに対して適用されるので、もちろん、associated-requirements(コンセプトの中のrequires)にも適用される。
auto concept BinaryIsoFunction< typename Op, typename Elem > {
requires std::Callable<Op, Elem, Elem>;
requires std::Convertible< std::Callable<Op, Elem, Elem>::result_type, Elem>;
typename result_type = std::Callable<Op, Elem, Elem>::result_type;
};
また、refinement clausesの(いわばコンセプトの継承とでも言うべき機能)、refinement-specifier でも使用できる。つまり、
concept Refining< typename T, typename U >
: Complicated<T,U>
{
requires std::HasPlus< Complicated<T,U>::result_type >;
} ;
ではなく、
concept Refining< typename T, typename U >
: c = Complicated<T,U>
{
requires std::HasPlus< c::result_type >;
} ;
とできる。