2016-05-21 6 views
3

私はちょうど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のバグでしょうか?

答えて

0

コンセプト名のコンセプトではなく、コンセプト名を操作することができます。バージョン3のコードではInputPredicate<InputIterator>ですが、InputIteratorは型名ではなく概念名です。したがって、コンパイルの失敗。

実際には、InputIteratorのコンセプトは、beginendのタイプで動作します。私は実際に好む

template<typename It, typename P> 
    requires InputIterator<It> && InputPredicate<P, It> 
bool all_of(It begin, It end, P pred) { 
    ... 
} 

を:それらに制約を配置するために句を必要とし、我々は明示的にテンプレートパラメータを指定して使用することができ、また

bool all_of(InputIterator begin, InputIterator end, 
     InputPredicate<decltype(begin)> pred) { 
    ... 
} 

:私たちは、関数のシグネチャを少し変更してこれを達成することができます後者の構文では、推測されるテンプレートパラメータに対する意図された制約がより明確になると私は考えている。

+0

'InputIterator'は、' InputPredicate 'に現れたときにプレースホルダとして使用されています。これは、' begin'と 'end'パラメータの宣言で使われるときと同じです。インスタンス化の時点でさえも、それ自体ではエラーではありません。 [その他のプレースホルダの例](http://coliru.stacked-crooked.com/a/ed52e1581b78d9d4) –

+0

興味深い。概念をプレースホルダとして記述するドキュメントはありますか?私は標準提案を見ても、そのユースケースに明示的に関係するものは見ませんでした。 –

関連する問題