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
Using Concept Checks
BOOST_CONCEPT_ASSERT()
コンセプトを満しているかを確認するマクロ。
cassertのassertに相当する。
# include "boost/concept_check.hpp"
template<typename T>
void generic_function(T x){
BOOST_CONCEPT_ASSERT((boost::EqualityComparable<T>));
// Do something
}
class foo{};
int main(){
int i = 2;
double a = 1.0;
generic_function(i);
generic_function(a);
foo f;
generic_function(f);
return 0;
}
g++ (GCC) 4.8.2 20131212 (Red Hat 4.8.2-7) で動作を確認している:
In file included from ./boost_concept_assert.cpp:2:0:
/usr/include/boost/concept_check.hpp: In instantiation of ‘boost::EqualityComparable<TT>::~EqualityComparable() [with TT = foo]’:
/usr/include/boost/concept/detail/general.hpp:39:28: required from ‘static void boost::concepts::requirement<boost::concepts::failed************ Model::************>::failed() [with Model = boost::EqualityComparable<foo>]’
./boost_concept_assert.cpp:6:5: required from ‘void generic_function(T) [with T = foo]’
./boost_concept_assert.cpp:17:23: required from here
/usr/include/boost/concept_check.hpp:237:30: エラー: no match for ‘operator==’ (operand types are ‘foo’ and ‘foo’)
require_boolean_expr(a == b);
^
/usr/include/boost/concept_check.hpp:238:30: エラー: no match for ‘operator!=’ (operand types are ‘foo’ and ‘foo’)
require_boolean_expr(a != b);
^
このように合同を判定するoperator (==, !=)が実装されていない場合、
コンパイル時にエラーとなる。
./boost_concept_assert.cpp:17:23: required from here
のように何処で問題が生じたか出力される上、比較演算子が無い旨がエラーメッセージに表示されている。
初心者にはまだ辛い表示だが。
ここで括弧が2重に必要な理由だが、本文では、
You can use this macro at any scope,
by passing a concept checking template specialization enclosed in parentheses.
Note: that means invocations of BOOST_CONCEPT_ASSERT will appear to use double parentheses.
とあるのみである。
ヘッダを読んだ感じ、以下のコードに相当する事をしている:
# define DEF(ARG) void(*)ARG
template<class Func>
class F{};
int main(){
F<DEF((double))> f;
return 0;
}
DEF((double))
が関数ポインタvoid(*)(double)
に展開されているのである。
BOOST_CONCEPT_ASSERT
がDEF
に相当し、関数ポインタを用いてTMPで変換可能がを判定している。
要は型だけを記述する構文が許されるのは関数ポインタの定義時だという事を用いている。
BOOST_CONCEPT_REQUIRES
C++11では採用されなかったが、
以下のように、テンプレート引数のclass
, typename
の代りに
conceptを記述する書き方が提案されていた:
syntax for declaring concept constrained function templates
# include <concepts>
template<std::CopyConstructible T>
T sum(T array[], int n)
{
T result = 0;
for (int i = 0; i < n; ++i)
result = result + array[i];
return result;
}
これに相当する事を既存の言語仕様下で実行するための方法がBOOST_CONCEPT_REQUIRES
である。
ドキュメントには以下のようなコードがある:
template<typename RanIter>
BOOST_CONCEPT_REQUIRES(
((Mutable_RandomAccessIterator<RanIter>))
((LessThanComparable<typename Mutable_RandomAccessIterator<RanIter>::value_type>)),
(void)) // return type
stable_sort(RanIter,RanIter);
これを解読するためには、まず
BOOST_CONCEPT_REQUIRES(
((Mutable_RandomAccessIterator<RanIter>))
((LessThanComparable<typename Mutable_RandomAccessIterator<RanIter>::value_type>)),
(void))
がRanIter
が適切な時、型void
になる事を理解する必要がある。
つまり
template<typename RanIter>
void stable_sort(RanIter, RanIter);
のvoid
の部分にむりやりBOOST_CONCEPT_ASSERT
に相当する物を埋め込んだのである。
これにより、関数の呼び出しの位置でエラーが発生する。
Multi-Type Concepts
2つ以上の型が関係するコンセプトも同様に定義できる。
同じなので略。
このようなコンセプトチェック機構はジェネリックライブラリの実装者のための物だが、
BOOST_CONCEPT_ASSERT((BidirectionalIterator<std::list<int>::iterator>));
のようにエンドユーザーがlist<int>
が双方向イテレータがどうか調べるためにも使える。