1

引数が の特定の概念であることを要求および確認するにはどうすればよいC++ですか?

たとえばrandom_shuffle、ヘッダー内の関数ではalgorithm、引数がRandomAccessIteratorsである必要があります。

  template<typename _RandomAccessIterator>
    inline void
    random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last)
    {
      // concept requirements
      __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
            _RandomAccessIterator>)
      __glibcxx_requires_valid_range(__first, __last);

      if (__first != __last)
        for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i)
          std::iter_swap(__i, __first + (std::rand() % ((__i - __first) + 1)));
    }

私は__glibcxx_function_requires自分のコードでこれらなどを使用できないと思いますか? それらはどのように機能しますか?コードでそのようなことをチェックしますか?

4

2 に答える 2

6

Boost には、このためのライブラリがあります。STL 実装者が一緒にハッキングしたバージョンの使用方法を理解するよりも、おそらく簡単で、十分に文書化されています。

http://www.boost.org/doc/libs/1_40_0/libs/concept_check/concept_check.htm

于 2009-09-27T21:02:05.533 に答える
2

_GLIBCXX_CONCEPT_CHECKSを定義しない限り、これらのマクロは離れて定義されます。だから私はこれを両方の方法でコンパイルしようとしました:

#include <list>
#include <algorithm>

int main()
{
    std::list<int> li;
    std::random_shuffle(li.begin(), li.end());
}

コンセプトチェックなし:8行のエラー-どのインスタンス化、ここで、演算子に一致しません。すべてが明確です。

コンセプトチェックあり:同じエラー+「ここからインスタンス化」の50行程度が、「エラー:「std::bidirection_iterator_tag」から非スカラー型「std::random_access_iterator_tag」への変換が要求されました」で終わるジブリッシュ。ドー!random_shuffleアルゴリズムにコメントがあれば、もっと早く理解できたはずです。

1つは、これらのチェックは必ずしも必要ではないということです。要件が満たされていない場合、コードはコンパイルに失敗します。そして、単純な「一致する演算子がない<」は、「関数には比較できない概念が必要である」と結論付ける(あいまいな言い回しで)50行のぎこちないものよりも明確であるように思われます。

これらのチェック(random_shuffleなど)が必要な場合、1つの方法は、適切なイテレータータグも受け入れる別の関数に呼び出しを転送することです。

#include <list>
#include <algorithm>
#include <iterator>
namespace detail {
template <class Iter>
void shuffle(Iter first, Iter last, std::random_access_iterator_tag)
{
    if (first != last)
        for (Iter i = first + 1; i != last; ++i)
            std::iter_swap(i, first + (std::rand() % ((i - first) + 1)));
}
}

template <class Iter>
void shuffle(Iter first, Iter last)
{
    detail::shuffle(first, last, typename std::iterator_traits<Iter>::iterator_category());
}

int main()
{
    std::list<int> li;
    shuffle(li.begin(), li.end());
}

素敵なメッセージを生成します:「'shuffle(std :: _ List_iterator&、std :: _ List_iterator&、std :: bidirection_iterator_tag)'の呼び出しに一致する関数がありません」

そして、あなたが超素敵になりたいのであれば、コンパイル時にアサートするテンプレート化されたオーバーロードを追加することができます(static_assertはC ++ 0xに付属しています):

template <class Iter, class Tag>
void shuffle(Iter, Iter, Tag )
{
    //test some template-dependent expression that is always false
    //to avoid it from firing unless the function is instantiated
    static_assert(sizeof(Tag) == 0, "shuffle requires random access iterators");
} 

ブーストのコンセプトチェックにはその場所がないと言っているわけではありません。

于 2009-09-28T22:57:59.820 に答える