具有多个模板参数的 C++ 概念
C++ Concepts with multiple template arguments
Bjarne Stroustrup 最近发表了一篇关于 C++ 概念的 report,他在其中提到了一些让我感到惊讶的事情。该示例(在第 7.1 节中)使用 "shorthand template notation" 并且基本上是这样的:
void foo1(auto x,auto y); // x and y may have different types (1)
void foo2(SomeConcept x,SomeConcept y); // x and y must have the same type (2)
就我个人而言,这似乎非常违反直觉;事实上,我希望 foo2 接受不同类型的值 x,y,只要各自的类型满足 SomeConcept。请注意,程序员始终可以通过编写以下内容之一来明确指定他的意图:
template <SomeConcept T> void foo2(T x, T y); // (3)
template <SomeConcept T1,SomeConcept T2> void foo2(T1 x,T2 y); // (4)
直觉上,我希望 (2) 中的 shorthand 表示法等同于 (4),因此更符合无约束模板 (1) 的含义。有人可以阐明这个问题并解释这个设计决定背后的基本原理吗?
一些备注:
- afaik,通用 lambda(在 C++14 中)已经允许类似于 (1) 的语法。因此,一致性决定了 (1) 应该接受不同类型的输入变量,因为通用 lambda 会那样做。
- Stroustrup 在此类模板的上下文中提到了经典的 "iterator pair"。但是,我认为这是一个相当薄弱的论点,因为 (i) 这只是一个用例,并且 (ii) afaik,C++17 引入了 (iterator, sentinel) 对,它强制通用代码无论如何都使用两种不同的类型.
我能找到的最早在当前概念提案的上下文中提到简洁语法的论文是 N3580,它在 §6.2.2 中提供了以下基本原理:
What if we need two argument types of the same concept? Consider
void sort(Ran p, Ran q);
For this to make sense, p
and q
must be of the same type, and that is the rule. By default, if you use the same constrained parameter name for two arguments, the types of those arguments must be the same. We chose to make repeated use of a constrained parameter name imply “same type” because that (in most environments) is the most common case and the aim here is to optimize for
terse notation of the simplest case. Also, a constrained parameter is the name
of a type, and having two type names refer to different types in the same scope
would cause chaos.
Tony van Eerd 和 Boton Ballo 提议更改此含义:P0464。该论文提供了两个支持当前含义的论据,一个类似于 Sutton 等人提出的一个,另一个是正交的:
Frequency of use
It can be argued that you don't often want a function that takes two arguments of potentially different types satisfying the same concept without having an additional relationship between the two types.
Interaction with definition checking
It can also be argued that this change will encourage template authors to write under-constrained templates, because they will opt to use the terse R foo(ConceptName, ConceptName);
form even in cases where in there should be an additional constraint on the parameter types. A proliferation of under-constrained templates will make the introduction of definition checking harder, because an under-constrained template will not pass definition checking.
我不熟悉支持当前语法的任何其他论点,但如果您熟悉,请随时给 Tony 和 Botond 发送电子邮件以将其纳入他们的论文。
为标记此问题或在 Google 上找到它的人快速更新。
此处讨论的问题已在 2018 年 3 月于杰克逊维尔举行的 C++ 标准会议之前得到解决——显然是悄无声息的。引用自 Botond's trip report:
As an aside, one topic that seems to have been settled without much discussion was the question of independent resolution vs. consistent resolution; that is, if you have two uses of the same concept in an AFT (as in void foo(Number, Number);
), are they required to be the same concrete type (“consistent”), or two potentially different types that both model the concept (“independent”). The Concepts TS has consistent resolution, but many people prefer independent resolution. I co-authored a paper arguing for independent resolution a while back; that sentiment was subsequently reinforced by another paper, and also in a section of the Sortable{S}
proposal. Somewhat to my amusement, the topic was never actually formally discussed and voted on; the idea of independent resolution just seemed to slowly, over time, win people over, such that by this meeting, it was kind of treated as a done deal, that any AFT proposal going into C++20 will, in fact, have independent resolution.
Bjarne Stroustrup 最近发表了一篇关于 C++ 概念的 report,他在其中提到了一些让我感到惊讶的事情。该示例(在第 7.1 节中)使用 "shorthand template notation" 并且基本上是这样的:
void foo1(auto x,auto y); // x and y may have different types (1)
void foo2(SomeConcept x,SomeConcept y); // x and y must have the same type (2)
就我个人而言,这似乎非常违反直觉;事实上,我希望 foo2 接受不同类型的值 x,y,只要各自的类型满足 SomeConcept。请注意,程序员始终可以通过编写以下内容之一来明确指定他的意图:
template <SomeConcept T> void foo2(T x, T y); // (3)
template <SomeConcept T1,SomeConcept T2> void foo2(T1 x,T2 y); // (4)
直觉上,我希望 (2) 中的 shorthand 表示法等同于 (4),因此更符合无约束模板 (1) 的含义。有人可以阐明这个问题并解释这个设计决定背后的基本原理吗?
一些备注:
- afaik,通用 lambda(在 C++14 中)已经允许类似于 (1) 的语法。因此,一致性决定了 (1) 应该接受不同类型的输入变量,因为通用 lambda 会那样做。
- Stroustrup 在此类模板的上下文中提到了经典的 "iterator pair"。但是,我认为这是一个相当薄弱的论点,因为 (i) 这只是一个用例,并且 (ii) afaik,C++17 引入了 (iterator, sentinel) 对,它强制通用代码无论如何都使用两种不同的类型.
我能找到的最早在当前概念提案的上下文中提到简洁语法的论文是 N3580,它在 §6.2.2 中提供了以下基本原理:
What if we need two argument types of the same concept? Consider
void sort(Ran p, Ran q);
For this to make sense,
p
andq
must be of the same type, and that is the rule. By default, if you use the same constrained parameter name for two arguments, the types of those arguments must be the same. We chose to make repeated use of a constrained parameter name imply “same type” because that (in most environments) is the most common case and the aim here is to optimize for terse notation of the simplest case. Also, a constrained parameter is the name of a type, and having two type names refer to different types in the same scope would cause chaos.
Tony van Eerd 和 Boton Ballo 提议更改此含义:P0464。该论文提供了两个支持当前含义的论据,一个类似于 Sutton 等人提出的一个,另一个是正交的:
Frequency of use
It can be argued that you don't often want a function that takes two arguments of potentially different types satisfying the same concept without having an additional relationship between the two types.Interaction with definition checking
It can also be argued that this change will encourage template authors to write under-constrained templates, because they will opt to use the terseR foo(ConceptName, ConceptName);
form even in cases where in there should be an additional constraint on the parameter types. A proliferation of under-constrained templates will make the introduction of definition checking harder, because an under-constrained template will not pass definition checking.
我不熟悉支持当前语法的任何其他论点,但如果您熟悉,请随时给 Tony 和 Botond 发送电子邮件以将其纳入他们的论文。
为标记此问题或在 Google 上找到它的人快速更新。
此处讨论的问题已在 2018 年 3 月于杰克逊维尔举行的 C++ 标准会议之前得到解决——显然是悄无声息的。引用自 Botond's trip report:
As an aside, one topic that seems to have been settled without much discussion was the question of independent resolution vs. consistent resolution; that is, if you have two uses of the same concept in an AFT (as in
void foo(Number, Number);
), are they required to be the same concrete type (“consistent”), or two potentially different types that both model the concept (“independent”). The Concepts TS has consistent resolution, but many people prefer independent resolution. I co-authored a paper arguing for independent resolution a while back; that sentiment was subsequently reinforced by another paper, and also in a section of theSortable{S}
proposal. Somewhat to my amusement, the topic was never actually formally discussed and voted on; the idea of independent resolution just seemed to slowly, over time, win people over, such that by this meeting, it was kind of treated as a done deal, that any AFT proposal going into C++20 will, in fact, have independent resolution.