LoginSignup
7
6

More than 5 years have passed since last update.

一人でBoost勉強会:Concept Check #2

Last updated at Posted at 2014-03-07

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に相当する。

boost_concept_assert.cpp
#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_ASSERTDEFに相当し、関数ポインタを用いて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>が双方向イテレータがどうか調べるためにも使える。

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6