_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");
}
ブーストのコンセプトチェックにはその場所がないと言っているわけではありません。