我想知道C ++完整概念提案和模板约束之间的语义差异(例如,Dlang或the new concepts-lite proposal for C++1y中出现的约束)。
什么是能够胜任模板约束的完整概念?
答案 0 :(得分:132)
以下信息已过期。它需要根据最新的Concepts Lite草案进行更新。
the constraints proposal的第3节以合理的深度涵盖了这一点。
The concepts proposal已被置于后燃烧器上一段时间,希望能够在更短的时间内充实约束(即概念 - 精简版),目前至少在C中实现某些目标++ 14。约束提议旨在平滑过渡到后来的概念定义。约束是概念提案的一部分,是其定义中必不可少的构建块。
在Design of Concept Libraries for C++中,Sutton和Stroustrup考虑以下关系:
概念=约束+公理
快速总结其含义:
因此,如果您将约束(语义属性)添加到约束(语法属性),您将获得概念。
概念精简提案只给我们带来了第一部分,即约束,但这是迈向成熟概念的重要而必要的步骤。
约束与语法有关。它们为我们提供了一种在编译时静态识别类型属性的方法,以便我们可以根据语法属性限制用作模板参数的类型。在当前的约束提议中,它们使用&&
和||
之类的逻辑连词来表达命题演算的子集。
让我们看一下行动中的约束:
template <typename Cont>
requires Sortable<Cont>()
void sort(Cont& container);
这里我们定义一个名为sort
的函数模板。新添加的是 requires子句。 requires子句为此函数的模板参数提供了一些约束。特别是,此约束表示类型Cont
必须是Sortable
类型。一个巧妙的事情是它可以用更简洁的形式写成:
template <Sortable Cont>
void sort(Cont& container);
现在,如果您尝试将任何不被视为Sortable
的内容传递给此函数,您将收到一个很好的错误,该错误会立即告诉您T
推导出的类型不是{ {1}}类型。如果您在C ++ 11中完成了这项工作,那么您在{em>内部 Sortable
函数中引发了一些可怕的错误,这对任何人都没有意义。
约束谓词与类型特征非常相似。他们采用一些模板参数类型,并为您提供一些信息。约束试图回答以下关于类型的问题:
但是,约束并不意味着替换类型特征。相反,他们将携手合作。现在可以根据概念和类型特征方面的某些概念来定义某些类型特征。
因此,关于约束的重要一点是它们并不关心语义。约束的一些好例子是:
sort
:检查类型是否Equality_comparable<T>
,两个操作数相同。
==
:检查是否存在具有给定类型的左右操作数的Equality_comparable<T,U>
==
:检查类型是否为算术类型。
Arithmetic<T>
:检查类型是否为浮点类型。
Floating_point<T>
:检查类型是否支持输入迭代器必须支持的语法操作。
Input_iterator<T>
:检查给定类型是否相同。
您可以使用特殊concepts-lite build of GCC尝试所有这些。
现在我们进入概念 - 精简提案之外的一切。这比未来本身更具未来感。 从现在开始的所有事情都可能会发生很大变化。
公理是关于语义的。它们指定了关系,不变量,复杂性保证和其他类似的东西。让我们来看一个例子。
虽然Same<T,U>
约束会告诉您有Equality_comparable<T,U>
类型operator==
和T
,但它并不能告诉您该操作是什么< EM>装置。为此,我们将有公理U
。这个公理说,当这两种类型的对象与给出Equivalence_relation
的{{1}}进行比较时,这些对象是等价的。这似乎是多余的,但肯定不是。您可以轻松定义operator==
,而不是true
。你这样做是邪恶的,但你可以。
另一个例子是operator==
公理。说operator<
类型的两个对象可以与Greater
和T
运算符进行比较,这一切都很好,但它们意味着什么? >
公理说iff <
大于Greater
,那么x
小于y
。建议的规范如此公理如下:
y
所以公理回答了以下类型的问题:
也就是说,他们完全关注这些类型的类型和操作的语义。这些东西无法静态检查。如果需要检查,类型必须以某种方式宣称它遵守这些语义。
以下是公理的一些常见例子:
x
:如果两个对象比较template<typename T>
axiom Greater(T x, T y) {
(x>y) == (y<x);
}
,则它们是等效的。
Equivalence_relation
:每当==
,然后Greater
。
x > y
:每当y < x
,然后Less_equal
。
x <= y
:对于!(y < x)
类型的Copy_equality
和x
:if y
,由复制构造创建的同一类型的新对象T
仍然x == y
(也就是说,它是非破坏性的)。
现在概念很容易定义;它们只是约束和公理的组合。它们提供了对类型的语法和语义的抽象要求。
例如,请考虑以下T{x} == y
概念:
x == y
首先请注意,对于模板类型Ordered
为concept Ordered<Regular T> {
requires constraint Less<T>;
requires axiom Strict_total_order<less<T>, T>;
requires axiom Greater<T>;
requires axiom Less_equal<T>;
requires axiom Greater_equal<T>;
}
,它还必须符合T
概念的要求。 Ordered
概念是一种非常基本的要求,该类型表现良好 - 可以构造,销毁,复制和比较。
除了这些要求之外,Regular
要求Regular
符合一个约束和四个公理:
Ordered
类型必须包含T
。这是静态检查,因此必须存在。Ordered
类型的operator<
和x
:
y
提供严格的总排序。T
大于x < y
时,x
小于y
,反之亦然。y
小于或等于x
时,x
不小于y
,反之亦然。y
大于或等于x
时,x
不大于y
,反之亦然。结合这样的约束和公理可以为您提供概念。它们定义了抽象类型的语法和语义要求,以便与算法一起使用。算法目前必须假设所使用的类型将支持某些操作并表达某些语义。通过概念,我们能够确保满足要求。
在the latest concepts design中,编译器只会检查模板参数是否满足概念的语法要求。公理未加控制。由于公理表示不具有静态可评估性(或通常无法完全检查)的语义,因此类型的作者必须明确声明其类型满足概念的所有要求。这在以前的设计中被称为概念映射,但后来被删除了。
以下是一些概念示例:
y
类型是可构造的,可破坏的,可复制的,并且可以进行比较。
x
类型支持Regular
,并且具有严格的总排序和其他排序语义。
Ordered
类型是可复制的,可销毁的,如果operator<
等于Copyable
且复制了x
,则副本也将等于{ {1}}。
y
类型必须包含自己必须符合某些概念的关联类型x
,y
,Iterator
和value_type
。他们还必须支持reference
并且可以取消引用。
约束是迈向C ++完整概念功能的第一步。它们是非常重要的一步,因为它们提供了类型的静态可执行要求,因此我们可以编写更清晰的模板函数和类。现在我们可以避免difference_type
及其元编程朋友的一些困难和丑陋。
但是,约束提案没有做很多事情:
它不提供概念定义语言。
约束不是概念图。用户不需要专门注释其类型满足某些约束。它们使用简单的编译时语言功能进行静态检查。
模板的实现不受其模板参数约束的约束。也就是说,如果您的函数模板对其不应该执行的约束类型的对象执行任何操作,则编译器无法对其进行诊断。一个功能齐全的概念提案可以做到这一点。
约束提案是专门设计的,因此可以在其上引入完整的概念提案。运气好的话,过渡应该是一个相当平稳的过程。概念组正在寻求为C ++ 14(或之后的技术报告)引入约束,而完整的概念可能会在C ++ 17的某个时候开始出现。
答案 1 :(得分:22)
参见最近(3月12日)概念电话会议纪要和讨论记录第2.3节中的“关于概念精简版的内容”,这些内容在同一天发布:http://isocpp.org/blog/2013/03/new-paper-n3576-sg8-concepts-teleconference-minutes-2013-03-12-herb-sutter。
答案 2 :(得分:4)
我的2美分:
概念精简提案并不意味着对模板实现进行“类型检查”。即,Concepts-lite将确保(在概念上)模板实例化站点的接口兼容性。引自论文:“concepts lite是C ++的扩展,允许使用谓词来约束模板参数”。就是这样。它并没有说将针对谓词检查(单独)模板体。这可能意味着当你谈论概念时,没有一流的 archtypes 概念。 archtypes,如果我没记错的话,在概念 - 重型提案中提供的类型不会少,也不会满足模板的实现。
concepts-lite使用glorified constexpr函数,编译器支持一些语法技巧。查找规则没有变化。
程序员不需要编写概念图。
最后,再次引用“约束提议并未直接解决语义的规范或使用;它仅针对检查语法。”这意味着公理不在范围内(到目前为止)。