N3701 concept lite

747 views

Published on

A presentation about Concepts Lite at C++14 Study meeting in Japan.

Published in: Technology, Education
  • Be the first to comment

  • Be the first to like this

N3701 concept lite

  1. 1. Concepts Lite N3701レビュー 2013/10/26 13:30 to 18:00 に開催された、C++14勉強会 http://atnd.org/events/44249 での発表内容に、その後のフォローアップ内容を追記 SC22WG21 エキスパート 近藤 貴俊 (株式会社オージス総研) 2014/1/30 1
  2. 2. Concepts Liteとは • テンプレートに制約を持たせることがで きる機能 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3701.pdf 2014/1/30 2
  3. 3. Convension class_name function_name new! Constraint_name TemplateParameter 第2区切りは出てこないかも 2014/1/30 3
  4. 4. 制約をかける Concepts Lite Syntax C++11ではテンプレート引数への制約を直接表現する方法が無い // Cont must be sortable template<typename Cont> void sort(Cont& container); 制約をコメントで記述 Concepts Liteの導入により、以下のように制約を記述することが可能 requires-expressionにより制約を記述 関数テンプレート template<typename Cont> requires Sortable<Cont>() void sort(Cont& container); typenameの箇所にconstraintを記述 同じ意味 template<Sortable Cont> void sort(Cont& container); templateの代わりにconcept-introductionを用いて記述 Sortable{Cont} void sort(Cont& container); 2014/1/30 4
  5. 5. 制約をかける Concepts Lite Syntax 制約違反の際、分かりやすい診断メッセージを出力可能 list<int> lst = ...; sort(lst); // Error error: no matching function for call to `sort(list<int>&)' sort(l); ^ note: candidate is: note: template<Sortable T> void sort(T) void sort(T t) { } ^ note: template constraints not satisfied because note: `T' is not a/an `Sortable' type [with T = list<int>] note: failed requirement with ('list<int>::iterator i', std::size_t n) note: `i[n]' is not valid syntax 2014/1/30 5
  6. 6. 制約をかける Concepts Lite Syntax 関数テンプレート クラステンプレート requires-clauseにより制約を記述 template<typename Cont> requires Sortable<Cont>() void sort(Cont& container); template<typename T, typename A> requires Object<T>() && Allocator<A>() class vector; typenameの箇所にconstraintを記述 template<Sortable Cont> void sort(Cont& container); template<Object T, Allocator A> class vector; templateの代わりにconcept-introductionを用いて記述 Sortable{Cont} void sort(Cont& container); Object{T} && Allocator{A} class vector; 2つ以上の独立した制約がある場合、 この表記は使えない 詳細は後述 2014/1/30 6
  7. 7. 制約をかける Concepts Lite Syntax クラステンプレートの部分特殊化 template<typename T, typename A> requires Object<T>() && Allocator<A>() class vector { クラステンプレートのメンバ関数 vector(const T& v) requires Copyable<T>(); void push_back(const T& x) requires Copyable<T>(); メンバ関数テンプレート template<Input_iterator I> vector(I first, I last); Forward_iterator{I} vector(I first, I last); }; 2014/1/30 template<typename T> struct foo; template<typename T> requires Cons1<T>() struct foo { ... }; template<Cons2 T> struct foo { ... }; Cons3{T} struct foo { ... }; Tに関する、当該メンバ関数 独自の制約 7
  8. 8. 表記が使えるとき使えないとき 制約をかける テンプ レート パラメタ の数 クラス テンプレート 成約の数 単 単 requires-clause を用いた表記 A typenameの constrained-parameter を用いた表記 concept-introduction を用いた表記 B C 単 template <typename T> requires Cons<T>() name; template<Cons T> name; Cons{T} name; 複 関数 テンプレート template <typename T> requires Cons<T,T>() name; 不可 template< typemane T, Cons<T> T> name; 不可 Cons{T,T} name; 無意味なので この行は無視して良い メンバ関数 テンプレート クラス テンプレートの 部分特殊化 制約 パラメタ の数 複 単 Tが2個定義されてしまうはず template < typename T, typename U > requires Cons<T>() name; template < Cons T, typename U > name; 不可 複 template < typename T, typename U > requires Cons<T,U>() name; template < typename U, Cons<U> T > name; Cons{T,U} name; Don't Care template < typename T, typename U > requires C1<T>() && C2<U>() name; template < C1 T, C2 U > name; 不可 における制約 Don't Care 2014/1/30 複 残念 全てのテンプレート引数が単 一のConceptの実引数である 場合しか使えない 残念 8
  9. 9. 表記が使えるとき使えないとき 制約をかける テンプ レート パラメタ の数 クラス テンプレート 成約の数 単 単 制約 パラメタ の数 A concept-introduction を用いた表記 B C 単 template <typename T> requires Cons<T>() name; template<Cons T> name; Cons{T} name; template <typename T> requires Cons<T,T>() name; 不可 template< typemane T, Cons<T> T> name; 不可 Cons{T,T} name; 単 template < typename T, typename U > requires Cons<T>() name; template < Cons T, typename U > name; 不可 template < typename T, typename U > requires Cons<T,U>() name; template < typename U, Cons<U> T > name; Cons{T,U} name; メンバ関数 テンプレート 複 における制約 複 2014/1/30 typenameの constrained-parameter を用いた表記 複 関数 テンプレート クラス テンプレートの 部分特殊化 requires-clause を用いた表記 残念 全てのテンプレート引数が単 一のConceptの実引数である 場合しか使えない Don't 複 Don't template < template < 不可 残念 concept Consは2つのテンプレート引数を持つ。しかしここでは1つしか指定されていない。 Care Care typename T, C1 T, この場合、Cons<U> を partial-concept-id と呼ぶ。 typename U C2 U 意味的には、Cons<_ , U> となり第1引数がプレースホルダーとして確保された状態となる。 > > これをrequiresに変換するには、 requires name; Cons<U> T で、Tを _ に代入し、requires Cons<T,U>() という意味になる。 C1<T>()→ Cons<_> で、_にTを代入し、requires Cons<T>() となる。 && C2<U>() Consの引数が1個の場合を考えてみると、Cons T name; この、部分適用的な機能は本当に必要だろうか? C があれば、ほとんど事足りる気がするが。 9
  10. 10. 制約をかける 関連するWording PDF P46 Standard Wording 7.1.6.5 Constrained type specifiers [dcl.spec.constrained] The type denoted by a concept-name or partial-concept-id is a constrained placeholder types. A constraint is formed from the application of the concept to the placeholder type. The placeholder type is used as the first template argument of the constraint. If the type specifier is a partial-concept-id, the specified arguments follow the placeholder type in the formed constraint. [Example: Real y = f(x); // decltype(y) is a placeholder type, 後で説明 // constrained by Real<decltype(y)> Same_as<T> a = f(b); // decltype(a) is a placeholder type, // constrained by Same_as<T, decltype(a)> — end example] 例がdecltype絡みばかりで 分かりにくい? 逆ではないか Same_asとはいえ 2014/1/30 10
  11. 11. 表記が使えるとき使えないとき 制約をかける テンプレート パラメタの数 制約 パラメタ の数 制約の数 requires-clause を用いた表記 A クラス テンプレート のメンバ関数 2014/1/30 Don't Care Don't Care Don't Care void mem_fun() requires Cons<T>(); typenameの constrainedparameter を用いた表記 conceptintroduction を用いた表記 B 不可 テンプレート宣言では ないため C 不可 テンプレート宣言で はないため 11
  12. 12. 制約をかける Corner Case? テンプレート パラメタの数 制約 パラメタ の数 成約の数 requires-clause を用いた表記 A クラス テンプレート 関数 テンプレート メンバ関数 テンプレート 複 複 複 template < typename T, typename U > requires C1<T, U>() && C2<U, T>() name; typenameの constrainedparameter を用いた表記 不可 template < typename T, C2<T> U ... C1が書けない conceptintroduction を用いた表記 B C 不可 クラス テンプレートの 部分特殊化 における制約 2014/1/30 12
  13. 13. 制約をかける A 制約のかけ方まとめ parserのカレントカーソルの 進む向きと考えると混乱する 冗長だが、全ての制約表記が可能 以前に定義されている 今後、定義されるかも と時間軸で とらえると分かりやすい template <typename T, typename U> requires Constraint1<T, U>() && Constraint2<U, T>() name; class hoge; // forward decl Conceptの引数が1つの場合、読みやすい記述が可能 前方 template <Constraint1 T, Constraint2 U> name; B 後方 typedef hoge fuga; class hoge {}; Conceptの引数の後方参照がある場合、表現できない C Conceptが1つで、全ての引数が制約されている場合に、読みやすい記述が可能 Constraint{T, U} name; 制約されない引数がある場合表現できない。 Conceptが複数ある場合、表現できない A は B と混ぜることができる A template <Constraint1 T, typename U> requires ConstraintX<T>() && ConstraintY<U>() name; 要確認 2014/1/30 OK と C は混ぜることができない Constraint{T} requires ConstraintX<T>() name 13
  14. 14. 制約のかけ方まとめ 制約をかける A 冗長だが、全ての制約表記が可能 template <typename T, typename U> requires Constraint1<T, U>() && Constraint2<U, T>() name; 割と何でも書けそう 14 Templates [temp] P48 template-declaration: template < template-parameter-list > requires-clauseopt declaration concept-introduction declaration requires-clause: requires-clause: requires constant-expression constant-expression の誤りではないだろうか? A template declaration with a requires-clause is a constrained template. A requires-clause introduces template constraints in the form of a constant-expression whose result type is bool. A declaration introduced by a concept-introduction (14.9.5) is a constrained template. 例えばこれは許される? template <typename T> true name; template <typename T> is_pointer<T>::value name; 2014/1/30 template <typename T> requires (T a, T b) { { a == b } -> bool; } name; 全ての例が requiresから 始まってるし この記述方法に ついては後述 14
  15. 15. 制約をかける B 制約のかけ方まとめ Conceptの引数が1つの場合、読みやすい記述が可能 template <Constraint1 T, Constraint2 U> name; 14.1 Template parameters [temp.param] P48 conceptキーワードを使って定義した concept definitionしか書けない constexpr関数名はNG 7.1.6 Simple type specifiers [dlt.type.simple] type-name: ... concept-name partial-concept-id concept-name: identifier partial-concept-id: concept-name < template-argument-list > P46 template-parameter: type-parameter parameter-declaration constrained-parameter constrained-parameter: constraint-id ...opt identifier constraint-id ...opt identifier = constrained-default-argument constraint-id: concept-name partial-concept-id constrained-default-argument: type-id template-name A constrained-parameter is introduced by a constraint-id, which is either a concept-name or a partial-concept-id. The concept definition referred to by the constraint-id determines the kind of template parameter and the constraints applied to that argument. P47 7.1.7 The concept specifier [dcl.concept] The concept specifier shall be applied to only the definition of a function template. A function template definition having the concept specifier is called a concept definition. 2014/1/30 イタリックにすべき? 15
  16. 16. 制約をかける C 制約のかけ方まとめ Conceptが1つで、全ての引数が制約されている場合に、読みやすい記述が可能 Constraint {T, U} name; 14 Templates [temp] conceptキーワードを使って定義した concept definitionしか書けない constexpr関数名はNG P48 template-declaration: template < template-parameter-list > requires-clauseopt declaration concept-introduction declaration requires-clause: constant-expression 14.9.5 Concept Introductions [temp.con.intro] P54 concept-introduction: concept-name { introduced-parameter-list } introduced-parameter-list: identifier introduced-parameter-list , identifier The concept name is matched, based on the number of introduced parameters to a corresponding concept definition. If no such concept can be found, the program is ill-formed. The kind of each introduced parameter (type, non-type, template), is the same as the corresponding template parameter in the matched concept definition. The concept is applied introduced parameters as a constraint on the trailing declaration. 2014/1/30 イタリックにすべき? 16
  17. 17. 制約をかける 非型パラメータの制約 template<size_t N> concept bool Prime() { return is_prime(N); } P29 ではconstexpr だが conceptの 誤記であろう conceptでないと、こうは書けないはず template<Object T, Prime N> class hash_array; template<typename T, size_t N> requires Object<T>() && Prime<N>() class hash_array; この書き方なら constexpr でもOK hash_array<int, 57> a; // Error 57は素数では無い 2014/1/30 17
  18. 18. 制約をかける Lambda Standard Wording はまだ無い vector<string> v = {...}; const char* str = "hello"; find_if(v, [str](const auto& x) { return str == x; }); [str](const auto& x) { return str == x; } 制約なし [str](const String& x) { return str == x; } B [str]<String T>(const T& x) { return str == x; } 繰り返しStringが出てくるとき短くTで書ける [str] String{T} (const T& x) { return str == x; } [] Input_query{I, P} (I first, I last, P pred) { ... } reqires表記はサポートされないため、表現能力には限界がある struct Functor { template <typename T, typename U> requires Cons1<T, U>() && Cons2<U, T>() void operator()(T, U) {} }; 例えばこれはlambdaで表現できない conceptを新たに定義すれば書けなくはないが 2014/1/30 C 制約として書けるのは おそらく concept definitionを満たす constrained-parameter 現状は concept name としか書いてない P11 constrained-parameter: constraint-id ...opt identifier constraint-id ...opt identifier = constrained-default-argument constraint-id: concept-name partial-concept-id template <typename T, typename U> concept bool My_constrain() { return requires { requires Cons1<T, U>(); requires Cons2<U, T>(); }; } [] (My_constrain{T, U} (T, U) { ... } 18
  19. 19. 制約をかける Auto autoが書けるところ全てを、conceptで置き換え可能にしようというアイデア generic lambdaを推し進めると次のように書けるようになる? 制約あり 制約無し auto gcd(auto a, auto b); Integer gcd(Integer a, Integer b); Integer制約を かける 上記は、下記と同義 template<typename T, typename U> auto gcd(T a, U b); 上記は、下記と同義 template<Integer T> T gcd(T a, T b); 制約無し template <typename T> auto begin(T&& t) -> decltype(t.begin()); Integer制約 template <typename T> Iterator begin(T&& t) -> decltype(t.begin()); 戻り値推論で template <typename T> Iterator begin(T&& t); A の書き方なら 2014/1/30 template <typename T> requires Iterator<decltype(declval<T>().begin())>() auto begin(T&& t); 19
  20. 20. 制約をかける Auto 変数も制約可能 auto y = f(x); Real y = f(x); Random_access_iterator r = find(p,q,v); 関数のオーバーロードセットを制約されたテンプレートに渡すことが可能 vector<double> v { ... }; Number n = accumulate(v.begin(), v.end(), operator*); Number n = accumulate(v.begin(), v.end(), [](auto a, auto b) { return operator*(a, b)}); accumulateのテンプレートパラメタが制約されていることが必須とのこと (詳細は不明) 2014/1/30 20
  21. 21. 制約の内容 制約の定義(concept) template<typename T> concept bool Equality_comparable() { ... } P47 7.1.7 The concept specifier [dcl.concept] The concept specifier shall be applied to only the definition of a function template. A function template definition having the concept specifier is called a concept definition. Every concept definition is also a constexpr declaration (7.1.5). Concept definitions have the following restrictions:  The template must be unconstrained.  The result type must be bool.  The declaration may have no function parameters. may?  The declaration must be defined.  The function shall not be recursive. 制約をconceptとして定義することで、以下の表記が可能となる B 2014/1/30 template <Constraint1 T, Constraint2 U> name; C Constraint{T, U} name; 21
  22. 22. 制約の内容定義 制約の内容 B C の表記を使わないのであれば constexpr でもよい template<typename T> concept bool Constraint() { return requires (T a, T b) { a++; a != b; // simple requirement {a == b} -> bool; { ++a } -> T&; { T(a) } noexcept constexpr; // compound-requirement typename T::value_type; // type-requirement requires Other_constraint<T>(); // nested-requirement }; } requres-expression 2014/1/30 22
  23. 23. 制約の内容定義 制約の内容 template<typename T> concept bool Constraint() { return requires (T a, T b) { a++; a != b; {a == b} -> bool; { ++a } -> T&; { T(a) } noexcept constexpr; typename T::value_type; 5.1.3 Requires expressions [expr.prim.requires] A requires expression provides a concise way to express syntactic requirements for template constraints. [Example: template<typename T> constexpr bool Readable() { かなり意味不明 return requires (T i) { (後ほど再検討) // simple requirement typename Value_type<T>; const Value_type<T>& = {*i}; }; // compound-requirement } — end example] P45 // type-requirement requires Other_constraint<T>(); // nested-requirement }; } 2014/1/30 P45 A requires-expression shall only appear inside a template. The type of a requires-expression is bool, and it is a constant expression. The requires-expression may be introduce local arguments via a parameterdeclaration-clause. These parameters have no linkage, storage, or lifetime. They are used as notation for the purpose of writing requirements. The body of requires-expression is a list of requirements. If each requirement in that list is satisfied, the result of the expression is true, or false otherwise. テンプレートの中にしか書けない(テンプレートの中ならconceptの中じゃなくても書ける) 式の値の型はbool。引数は、制約記述のためにローカル変数的に用いられ、リンケージや ライフタイムは持たない。内容は制約のリストで、全リストがtrueならrequires-expressionの値が trueとなり、そうでなければ falseとなる。 23
  24. 24. 制約の内容定義 制約の内容 template<typename T> concept bool Constraint() { return requires (T a, T b) { a++; a != b; // simple requirement P45 5.1.3.1 Simple requirements [expr.req.simple] {a == b} -> bool; // compound-requirement A simple-requirement introduces a requirement that the expression is a valid { ++a } -> T& expression } noexcept constexpr; instantiation of the constraint results in { T(a) when instantiated. If the a substitution failure, the the requirement is not satisfied. typename T::value_type; // type-requirement requires Other_constraint<T>(); // nested-requirement }; } 2014/1/30 24
  25. 25. 制約の内容 制約の内容定義 P45 5.1.3.2 Compound requirements [expr.req.compound] A compound-requirement introduces a set of requirements involving a single template<typename T> expression. The expression must compile when instantiated. concept bool Constraint() If a result-type-requirement is present then the result type of the instantiated { expression must satisfy that requirement. If the required type-id is a constrained return requires (T a, those constraints must also be satisfied. placeholder type (7.1.6.5), thenT b) { a++; // simple requirement If the constexpr specifier is present, the instantiated expression must be constexpr-evaluable. a != b; If the noexcept specifier is present, instantiated expression must not propagate exceptions. {a == b} -> bool; { ++a } -> T&; { T(a) } noexcept constexpr; 2014/1/30 // compound-requirement 戻り値がboolに変換可能なら制約を満たすといったケースを satisfy that requirementでは明言できていない気がする。 that requirementはresult-type-requirementを指すはず。 7.1.6.5 Constrained type specifiers [dcl.spec.constrained] typename T::value_type; // type-requirement P46 The type denoted by a concept-name or partial-concept-id is a constrained placeholder types. A onstraint is formed from the application of the concept to the placeholder type. The placeholder type requires Other_constraint<T>(); // nested-requirement is used as the first template argument of the constraint. If the type specifier is a partial-concept-id, the specified arguments follow the placeholder type in the formed constraint. [Example: }; Real y = f(x); // decltype(y) is a placeholder type, } // constrained by Real<decltype(y)> Same_as<T> a = f(b); // decltype(a) is a placeholder type, 戻り値が別のConstraind placeholder typeの場合は // constrained by Same_as<T, decltype(a)> ここで説明できている — end example] The first use of concept-name or partial-concept-id within a scope binds that name to the placeholder type so that subsequent uses of the same name refer to the same type. [Example: template<typename T> concept bool Number() { ... } auto mul = [](Number a, Number b) { return a * b; } The types of a and b are the same. This is equivalent to having written: auto mul = []<Number N>(N a, N b) { return a * b; } — end example] 25
  26. 26. 制約の内容定義 制約の内容 template<typename T> concept bool Constraint() { return requires (T a, T b) { a++; a != b; // simple requirement {a == b} -> bool; { ++a } -> T&; { T(a) } noexcept constexpr; typename T::value_type; } 2014/1/30 // compound-requirement // type-requirement P45 5.1.3.3 Type requirements [expr.req.type] requires Other_constraint<T>(); // nested-requirement A type-requirement introduces a requirement that an associated type name can be formed when instantiated. If the instantiation of the type requirement results }; in a substitution failure, the requirement is not satisfied. 26
  27. 27. 制約の内容 制約の内容定義 template<typename T> concept bool Constraint() { return requires (T a, T b) { a++; a != b; // simple requirement {a == b} -> bool; { ++a } -> T&; { T(a) } noexcept constexpr; // compound-requirement typename T::value_type; // type-requirement requires Other_constraint<T>(); // nested-requirement P46 5.1.3.4 Nested requirements [expr.req.type] }; nested requirement introduces additional constraints to be evaluated as part A } of the requires expression. The requires-clause is constexpr evaluated, and the requirement is satisfied only when that evaluation yields true. 2014/1/30 27
  28. 28. オーバーロードの解決 template<Container C> void f(const C& c); // #1 template<Forward_iterator I> void f(I i); // #1 template<typename S> requires Container<S>() || Range<S>() void f(const S& s); // #2 template<Random_access_iterator I> void f(I i); // #2 ... template<Equality_comparable T> void f(const T& x); // #3 vector<int> v { ... }; f(v.begin()) // calls #2 ... vector<int> v { ... }; list<int> l { ... }; f(l.begin()) // calls #1 f(v) // calls #1 f(filter(v, even)); // calls #2 f(0); // calls #3 2014/1/30 28
  29. 29. オーバーロードの解決 logical-and && logical-or concept check || Concept_name<T>() 左記以外の expression atomic proposition 14.9.1 Constraint reduction [temp.con.reduce] A constrained template’s actual constraints are reduced by inlining concept checks, and producing an expression comprised of only atomic propositions and logical-andexpressionss and logical-or-expressions. reduceされたイメージ && && atomic proposition || atomic proposition 14.9.2 Constraint Satisfaction [temp.con.sat] A template’s constraints are satisfied if the constexpr evaluation of the reduced constraints results in true. 2014/1/30 P52 P52 29
  30. 30. オーバーロードの解決 14.5.6.2 Partial ordering of function templates [tmp.func] Partial ordering selects which of two function templates is more specialized than the other by transforming each template in turn (see next paragraph) and performing template argument deduction using the function type. The deduction process determines whether one of the templates is more specialized than the other. If so, the more specialized template is the one chosen by the partial ordering process. If both deductions succeed, the the more specialized template is the one that is more constrained (14.9.3). P51 より制約された方が、よりspecializedされたテンプレートである 2014/1/30 30
  31. 31. オーバーロードの解決 P53 14.9.3 Partial ordering of constraints [temp.con.ord] Partial ordering of constraints is used to choose among ambiguous specializations during the partial ordering of function templates, the partial ordering of class templates, and the use of template template arguments. The partial ordering of two reduced constraints P and Q determines if P subsumes Q. Determining the partial ordering of reduced constraints requires their decomposition into a list of lists of atomic propositions. Decomposition of a reduced constraint P begins with a single list (the current list) containing the reduced constraint P (the current term). Decomposition proceeds by analyzing the current term.  If P is of the form a && b, then replace P in the current list with the operands a and b so that a is the current term and b will be the next term.  If P is of the form a || b, then create a copy of the current list, replacing P with a in the original and replacing P with b in the copy so that a is the current term in the original and b is the current term in the copy.  Otherwise, advance to the next term. If there are no remaining terms, advance to the next list. If there are no remaining lists, decomposition terminates. Given two reduced constraints P and Q, then P subsumes Q only if all of Q’s atomic propositions can be found in the P. Denote this comparison as P ⊢ Q. This is computed by first decomposing P into a list of lists of atomic propositions, L, and then comparing the expression Q against each list Li in L, which is equivalent to determining if Li ⊢ Q according to the following rules:  If Q is of the form a && b, then Li ⊢ Q if and only if Li ⊢ a and Li ⊢ b.  If Q is of the form a || b, then Li ⊢ Q if and only if Li ⊢ a or Li ⊢ b.  Otherwise Li ⊢ Q if and only if there exist some atomic proposition A in Li that matches Q (14.9.4). Only when each Li ⊢ Q does P ⊢ Q. For two template declarations with equivalent type, the first is at least as constrained as the second if both templates are unconstrained, the first is constrained and the second unconstrained, or the constraints of the first subsume the constraints of the second. 2014/1/30 x ⊢ y means y is derivable from x. y は x から推論できる。 31
  32. 32. オーバーロードの解決 A && B && C A && B || C && A || B && C || && && && A B A C B C || A B A C A B B A atomic proposition の 集合 のリストを形成する C B C C C A || (B && C) || 集合 A B && リスト 集合 C A B B C C A 2014/1/30 32
  33. 33. オーバーロードの解決 満たされている制約 テンプレートの制約 P A || B A Q A P A A A B Q A && B A B A A B P A B P A B Q A B Q A B Qがより制約されている Q は P に含まれる P は Qに含まれない 2014/1/30 Pがより制約されている Pを満たすなら常にQ満たす Qを満たしてもPを満たして いるとは限らない P は Q に含まれる Q は Pに含まれない 満たされている制約は候補に挙げるか否かの判断に使うだけで、 どちらがより制約されているかの判断には使わない 確信が持てない 33
  34. 34. オーバーロードの解決 P A B C Q A || (B && C) A B A C P (A && B) || C B A B C A && B A Q C B C C A A P B C B A A Q B B C PQ同レベル 2014/1/30 C C PQ同レベル 34
  35. 35. オーバーロードの解決 P Q A && B || C A && B && C || && && && A B A A C B B A B C C C 満たすatomic proposition 選択されるオーバーロード A - - B - - C P P: P.C AB P P: P.AB BC P P: P.C CA P P: P.C ABC 2014/1/30 成立する 制約 P,Q Q: Q.ABC (P.AB と P.C の両方が Q.ABCに包含される) 35
  36. 36. オーバーロードの解決 P Q (A && B&& C) || D || E A B (A && B)|| C || (D && E) C A D A C E D B B D E A C B E D C 満たすatomic proposition 成立する 制約 選択されるオーバーロード A - - C Q Q D P P ABC P,Q 両方 DE P,Q ABCD P,Q ABCDE 2014/1/30 E P,Q もし、非テンプレート引数のimplicit conversionが絡まなければ、 両方== 曖昧 でエラーとなる implicit conversionが関係するケースは次ページで検討 36
  37. 37. オーバーロードの解決 Container ⊃ Equality_comparable // #1 template <Container C> void foo(C c, int i); // #2 template <Equality_comparable Ec> void foo(Ec ec, double d); std::vector<int> v; foo(v, 1); // call #1 foo(v, 12.3); // call #1 vは#1に、よりマッチする。12.3 は #2に、よりマッチする。 今回新たに導入された制約のマッチ度合いと、これまでも存在したimplicit conversionの必要性 によるマッチ度合いがどう評価されるのか記述が見つからない。 https://groups.google.com/a/isocpp.org/forum/#!topic/concepts/67H0UOXe03g によれば、非テンプレート引数のConversionの方が、Constraintよりも優先されるとのこと。 P293 13.3 Overload resolution [over.match] But, once the candidate functions and argument lists have been identified, the selection of the best function is the same in all cases: — First, a subset of the candidate functions (those that have the proper number of arguments and meet certain other conditions) is selected to form a set of viable functions (13.3.2). — Then the best viable function is selected based on the implicit conversion sequences (13.3.3.1) needed to match each argument to the corresponding parameter of each viable function. 2014/1/30 37
  38. 38. Standard Wording への指摘 5.1.3 Requires expressions [expr.prim.requires] P45 A requires expression provides a concise way to express syntactic requirements for template constraints. [Example: template<typename T> constexpr bool Readable() { return requires (T i) { このような表記は許されていないのでは? typename Value_type<T>; const Value_type<T>& = {*i}; }; } — end example] エスパーすると、こう書きたかったのか? constexpr でもいいけど conceptにしない理由がない template<typename T> concept bool Readable() { return requires (T i) { typename T::value_type; {*i} -> const typename T::value_type&; }; } 2014/1/30 38
  39. 39. Standard Wording への指摘 P46 7.1.6.5 Constrained type specifiers [dcl.spec.constrained] The type denoted by a concept-name or partial-concept-id is a constrained place-holder types. A constraint is formed from the application of the concept to the placeholder type. The placeholder type is used as the first template argument of the constraint. If the type specifier is a partial-concept-id, the specified arguments follow the placeholder type in the formed constraint. [Example: Real y = f(x); // decltype(y) is a placeholder type, // constrained by Real<decltype(y)> Same_as<T> a = f(b); // decltype(a) is a placeholder type, // constrained by Same_as<T, decltype(a)> — end example] 逆ではないか Same_asとはいえ Concept_name { a, b} という表記がある今、 そもそも、この関数の部分適用みたいなの必要なの?という議論もある 2014/1/30 39
  40. 40. Standard Wording への指摘 P47 7.1.7 The concept specifier [dcl.concept] The concept specifier shall be applied to only the definition of a function template. A function template definition having the concept specifier is called a concept definition. Every concept definition is also a constexpr declaration (7.1.5). Concept definitions have the following restrictions:  The template must be unconstrained.  The result type must be bool. shall have または must have ではないか?  The declaration may have no function parameters.  The declaration must be defined.  The function shall not be recursive. 2014/1/30 40
  41. 41. Standard Wording への指摘 14 Templates [temp] P48 template-declaration: template < template-parameter-list > requires-clauseopt declaration concept-introduction declaration requires-clause: requires-clause: requires constant-expression constant-expression の誤りではないだろうか? 2014/1/30 41
  42. 42. Standard Wording への指摘 14.1 Template parameters [temp.param] P48 template-parameter: type-parameter parameter-declaration constrained-parameter constrained-parameter: constraint-id ...opt identifier constraint-id ...opt identifier = constrained-default-argument constraint-id: concept-name partial-concept-id constrained-default-argument: type-id template-name 改行が必要と思われる 2014/1/30 42
  43. 43. Standard Wording への指摘 14.3.3 Template template arguments [tmp.arg.template] A template-argument matches a template template-parameter (call it P) when each of the template parameters in the template-parameter-list of the templateargument’s corresponding class template or alias template (call it A) matches the corresponding template parameter in the template-parameter-list of P, and when P is not less constrained (14.9.3) than A. [Example // ... from standard P50 template<template<Copyable>> class C> class stack { ... }; template<Regular T> class list1; template<Object T> class list1; list2の誤りと思われる stack<list1> s1; // OK: Regular is more constrained than Copyable stack<list2> s2; // error: Object is not more constrained than Copyable — end example] 14.9.5 Concept Introductions [temp.con.intro] P54 concept-introduction: concept-name { introduced-parameter-list } introduced-parameter-list: identifier introduced-parameter-list , identifier 改行が必要と思われる 2014/1/30 43

×