Note for Boost Concept Check Library (BCCL)
以下の記述は公式のドキュメントを自分なりに要約した物であり、
和訳を目指す物ではない。
また内容を保証するものでもない。
Index
- #1 Concept Checking Introduction
- #2 Using Concept Checks
- #3 Creating Concept Checking Classes
- #4 Concept Covering and Archetypes
Creating Concept Checking Classes
いよいよ実際にコンセプトをチェックするクラスを実装する部分を説明する。
ここではまず入力反復子(InputIterator)である事を確認するクラスを作成する。
今まではあるイテレータがある時、それが入力反復子である事を厳密に確認する手段はなかった。
次に示すテンプレートクラスは入力演算子の厳密な定義を与える:
template <class X>
struct InputIterator
: Assignable<X>, EqualityComparable<X>
{
private:
typedef std::iterator_traits<X> t;
public:
typedef typename t::value_type value_type;
typedef typename t::difference_type difference_type;
typedef typename t::reference reference;
typedef typename t::pointer pointer;
typedef typename t::iterator_category iterator_category;
BOOST_CONCEPT_ASSERT((SignedInteger<difference_type>));
BOOST_CONCEPT_ASSERT((Convertible<iterator_category, std::input_iterator_tag>));
BOOST_CONCEPT_USAGE(InputIterator)
{
X j(i); // require copy construction
same_type(*i++,v); // require postincrement-dereference returning value_type
X& x = ++j; // require preincrement returning X&
}
private:
X i;
value_type v;
// Type deduction will fail unless the arguments have the same type.
template <typename T>
void same_type(T const&, T const&);
};
以降ではこのようなconcept checking classを単にコンセプトと呼ぶ。
他のコンセプトの継承
template <class X>
struct InputIterator
: Assignable<X>, EqualityComparable<X>
まずこの部分を考えよう。
あるコンセプトを実装しようと思う時、その全ての条件が独自である事は少ないだろう。
特に自作のライブラリ内のコンセプトだとなおさらである。
この時、既に存在しているコンセプトを利用できると嬉しいし、そうすべきである。
BCCLではこれをテンプレートクラスの継承を利用して実現する。
まず入力演算子は代入可能(Assignable)で、比較可能(EqualityComparable)である必要がある。
この部分を上述の継承の部分で実装している。
もしInputIteratorクラスの本体の実装せずとも、クラスXがAssignableでEqualityComparableである事がテストされる。
traitsのチェック
private:
typedef std::iterator_traits<X> t;
public:
typedef typename t::value_type value_type;
typedef typename t::difference_type difference_type;
typedef typename t::reference reference;
typedef typename t::pointer pointer;
typedef typename t::iterator_category iterator_category;
これはtraitsが定義されている事を確認している。
BOOST_CONCEPT_ASSERT((SignedInteger<difference_type>));
BOOST_CONCEPT_ASSERT((Convertible<iterator_category, std::input_iterator_tag>));
これは前回説明した BOOST_CONCEPT_ASSERT
で、
使い方もそのままなので略。
BOOST_CONCEPT_USAGE
これがkeyとなる部分だろう。
BOOST_CONCEPT_USAGE(InputIterator)
{
X j(i); // require copy construction
same_type(*i++,v); // require postincrement-dereference returning value_type
X& x = ++j; // require preincrement returning X&
}
これはsyntaxが有効かどうかを調べている。実際にこのコードが実行される事はない。
at this point you may sometimes need to be a little creative
と言っている通り、この部分を実装するのがもっとも大変だろう。
例えば*i++
がX
型を返す事を確認するために、補助関数same_type
を導入している。
この部分はTMP用のライブラリを使用する方がいいだろう。
Values for Usage Patterns Should Be Data Members
ここでBOOST_CONCEPT_USAGE
に使用するデータメンバーを
X i;
value_type v;
のようにデータメンバーとして定義するのは、
X
がデフォルトコンストラクタを持たなくてもよくなるためである。
since instances of the InputIterator template will never be constructed, the compiler never has to check how its data members will be constructed (C++ Standard Section 14.7.1 9)
とある通り、データメンバーは初期化されないので、
BOOST_CONCEPT_USAGE
で使用するインスタンスはデータメンバーとして定義する必要がある。
Similarity to Proposed C++0x Language Support for Concepts
他の提案されているsyntaxとの関係が述べてある。
この部分はおそらく古いので、いずれ調べる。