私はちょうどg ++ 6.1.0(Debianパッケージバージョン6.1.1-1、フラグ-std=c++17 -fconcepts
)を使ってC++のコンセプトを実験し始めました。次のような縮小された例ではわかりません。生成されたテンプレートに特定のコンセプト制約が重複しているのはなぜですか?
#include <iterator>
#include <vector>
#include <iostream>
template <typename B>
concept bool ContextualBool = requires(B b) {
{ bool(b) };
{ !b } -> bool;
};
template <typename It>
concept bool InputIterator = requires(const It iconst, const It jconst, It i) {
typename std::iterator_traits<It>::reference;
typename std::iterator_traits<It>::value_type;
{ iconst == jconst } -> ContextualBool;
{ iconst != jconst } -> ContextualBool;
{ *i } -> typename std::iterator_traits<It>::reference;
{ ++i } -> It&;
{ *i++ } -> typename std::iterator_traits<It>::value_type;
};
template <typename P, typename Arg>
concept bool Predicate = requires(P pred, Arg x) {
{ pred(x) } -> ContextualBool;
};
template <typename P, typename It>
concept bool InputPredicate = requires {
typename std::iterator_traits<It>::reference;
requires Predicate<P, typename std::iterator_traits<It>::reference>;
};
/* Version 1 */
/*
InputIterator{I}
bool all_of(I begin, I end, InputPredicate<I> pred) {
*/
/* Version 2 */
/*
bool all_of(InputIterator begin, InputIterator end,
Predicate<typename std::iterator_traits<InputIterator>::reference> pred) {
*/
/* Version 3 */
bool all_of(InputIterator begin, InputIterator end,
InputPredicate<InputIterator> pred) {
while (begin != end) {
if (!pred(*begin))
return false;
++begin;
}
return true;
}
int main() {
std::vector<int> v { 1, 2, 3, 4, 5 };
if (all_of(v.begin(), v.end(), [](int n) { return n % 2 == 0; }))
std::cout << "All elements of v are even\n";
return 0;
}
このコードでは、バージョン1とバージョン2の両方が予想される実行時の結果で正常にコンパイルされます。ただし、バージョン3で、私は次のエラーメッセージを取得する:エラーメッセージから
/tmp/concepts_repr.cpp: In function ‘int main()’:
/tmp/concepts_repr.cpp:56:70: error: no matching function for call to ‘all_of(std::vector<int>::iterator, std::vector<int>::iterator, main()::<lambda(int)>)’
if (all_of(v.begin(), v.end(), [](int n) { return n % 2 == 0; }))
^
/tmp/concepts_repr.cpp:44:10: note: candidate: template<class auto:1, class auto:2, class auto:3, class auto:4> requires predicate(InputIterator<auto:1>) and predicate(InputPredicate<auto:2, auto:1>) and predicate(InputIterator<auto:3>) and predicate(InputPredicate<auto:4, auto:3>) bool all_of(auto:1, auto:1, auto:4)
bool all_of(InputIterator begin, InputIterator end,
^~~~~~
/tmp/concepts_repr.cpp:44:10: note: template argument deduction/substitution failed:
/tmp/concepts_repr.cpp:56:70: note: couldn't deduce template parameter ‘auto:2’
if (all_of(v.begin(), v.end(), [](int n) { return n % 2 == 0; }))
^
は、それはいくつかの理由で生成されたテンプレートでInputIteratorとInputPredicateテンプレートパラメータの重複バージョンを生産ているように見えます。私はなぜこれが、特にバージョン2が働いているかを理解できません。私はcppreference.comからのステートメントを誤解しています: "同等の制約付きタイプ指定子によって導入されたすべてのプレースホルダは、同じ発明テンプレートパラメータを持っています"?あるいはgccのバグでしょうか?
'InputIterator'は、' InputPredicate 'に現れたときにプレースホルダとして使用されています。これは、' begin'と 'end'パラメータの宣言で使われるときと同じです。インスタンス化の時点でさえも、それ自体ではエラーではありません。 [その他のプレースホルダの例](http://coliru.stacked-crooked.com/a/ed52e1581b78d9d4) –
興味深い。概念をプレースホルダとして記述するドキュメントはありますか?私は標準提案を見ても、そのユースケースに明示的に関係するものは見ませんでした。 –