概念和模板约束之间有什么区别?

我想知道C ++完整概念提案和模板约束(例如,Dlang中出现的约束或C ++ 1y的新概念精简build议 )之间的语义差异。

什么是比模板约束能做的完整概念不能做到的?

以下信息已过时。 它需要根据最新的Concepts Lite草案进行更新。

约束提议的第3部分涵盖了这个问题的合理深度。

这个概念提案已经在短时间内被放在了后面的燃烧器上,希望能够在更短的时间范围内实现约束(即概念 – 概念),而目前的目标至less是C ++中的某些东西。 这个约束build议被devise成向后面的概念定义的平滑过渡。 制约因素是概念提案的一部分,是其定义中必不可less的组成部分。

在C ++ ,Sutton和Stroustrup 的概念库devise中 ,考虑以下关系:

概念=约束+公理

要快速总结其含义:

  1. 约束 – 一个静态可评估的属性types的谓词。 纯粹的句法要求。 不是域抽象。
  2. 公理 – 假定为真的types的语义要求。 没有静态检查。
  3. 概念 – 一般,对其参数的algorithm的抽象要求。 用约束和公理来定义。

所以,如果你添加公理(语义属性)的约束(语法属性),你会得到概念。


概念 – 精简版

概念精简的build议只给我们带来了第一部分的约束,但这是走向完整概念的一个重要的必要步骤。

约束

约束都是关于语法的 。 它们给了我们一种在编译时静态辨别types属性的方法,以便我们可以根据它们的语法属性限制用作模板参数的types。 在当前的约束build议中,它们用命题演算的一个子集来表示,使用逻辑连接词如&&||

让我们来看看一个行动的约束:

 template <typename Cont> requires Sortable<Cont>() void sort(Cont& container); 

这里我们定义了一个名为sort的函数模板。 新增加的是要求条款 。 require子句为该函数的模板参数提供了一些约束。 特别是,这个约束表示typesCont必须是一个Sortabletypes。 一个整洁的事情是,它可以写成一个更简洁的forms:

 template <Sortable Cont> void sort(Cont& container); 

现在,如果您尝试将不被视为可Sortable任何内容传递给此函数,您将得到一个很好的错误,并立即告诉您为T推导的types不是可Sortabletypes。 如果你已经在C ++ 11中完成了这个工作,那么在sort函数里面会有一些可怕的错误,这对任何人都是没有意义的。

约束谓词与types特征非常相似。 他们采取一些模板参数types,并给你一些关于它的信息。 约束条件试图回答关于types的以下几种问题:

  1. 这个types是否有这样的运算符重载?
  2. 这些types可以用作操作符吗?
  3. 这种types有这样的特质吗?
  4. 这个常数expression式等于那个吗? (对于非types的模板参数)
  5. 这个types是否有一个叫做yada-yada的函数返回这个types?
  6. 这个types是否满足所有的语法要求?

但是,限制并不意味着取代types特征。 相反,他们将携手并进。 现在可以根据概念和types特征来定义一些types特征。

例子

所以关于约束的重要之处在于他们不关心一个iota的语义。 约束的一些很好的例子是:

  • Equality_comparable<T> :检查相同types的两个操作数是否具有==types。

  • Equality_comparable<T,U> :检查给定types的左右操作数是否存在==

  • Arithmetic<T> :检查types是否是算术types。

  • Floating_point<T> :检查types是否为浮点types。

  • Input_iterator<T> :检查types是否支持input迭代器必须支持的语法操作。

  • Same<T,U> :检查给定types是否相同。

你可以用一个特殊的概念构buildGCC来尝试所有这些。


超越Concepts-Lite

现在我们进入超越概念提案的一切。 这比未来本身更加未来主义。 从这里开始的一切都可能会发生很大的变化。

公理

公理都是关于语义的 。 它们指定了关系,不variables,复杂性保证等等。 我们来看一个例子。

虽然Equality_comparable<T,U>约束会告诉你有一个operator==需要typesTU ,但它并不告诉你这个操作什么意思 。 为此,我们将有公理Equivalence_relation 。 这个公理说,当这两种types的对象与operator==相比较时,这些对象是等价的。 这可能看起来多余,但肯定不是。 你可以很容易地定义一个operator== ,而不像operator< 。 你会做坏事,但你可以。

另一个例子是一个Greater公理。 说T型的两个对象可以与“和<操作符进行比较是好的,但它们什么意思Greater公理说,如果x大于y ,那么y小于x 。 拟议的规范如此公理如下:

 template<typename T> axiom Greater(T x, T y) { (x>y) == (y<x); } 

因此,公理回答以下几类问题:

  1. 这两个运营商是否有这种关系?
  2. 这种types的操作符是否意味着这个?
  3. 这种types的操作是否有这种复杂性?
  4. 这个操作符的结果是否意味着这是真的?

也就是说,他们完全关心这些types的types和操作的语义。 这些东西不能被静态检查。 如果这需要检查,一个types必须以某种方式宣布它遵守这些语义。

例子

这里有一些公理的例子:

  • Equivalence_relation :如果两个对象比较== ,则它们是等价的。

  • Greater :只要x > y ,那么y < x

  • Less_equal :当x <= y ,则!(y < x)

  • Copy_equality :对于typesT xy :如果x == y ,通过复制构造T{x} == y创build的同一types的新对象仍然是x == y (即它是非破坏性的) 。

概念

现在概念很容易定义, 它们只是约束和公理结合 。 它们提供了对一个types的语法和语义的抽象要求。

作为一个例子,考虑下面的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>; } 

首先要注意的是,对于需要Ordered的模板typesT ,它也必须满足Regular的要求。 Regular概念是一个非常基本的要求,types是行为良好的 – 它可以被构build,销毁,复制和比较。

除了这些要求之外, Ordered要求T符合一个约束和四个公理:

  • 约束: Orderedtypes必须有一个operator< 。 这是静态检查,所以它必须存在。
  • 公理:对于T型的xy
    • x < y给出严格的总sorting。
    • x大于yy小于x ,反之亦然。
    • x小于或等于yy不小于x ,反之亦然。
    • x大于或等于yy不大于x ,反之亦然。

结合这样的限制和公理给你的概念。 他们定义了用于algorithm的抽象types的语法和语义要求。 algorithm目前不得不假设所使用的types将支持某些操作并expression某些语义。 有了概念,我们就能够确保符合要求。

在最新的概念devise中 ,编译器只会检查模板参数是否满足概念的语法要求。 这些公理没有被检查。 由于公理表示不是静态可评估的语义(或者通常不可能完全检查),因此types的作者必须明确地声明他们的types符合概念的所有要求。 这在之前的devise中被称为概念图,但是已经被移除。

例子

以下是一些概念的例子:

  • Regulartypes是可构造的,可破坏的,可复制的,并可以进行比较。

  • Orderedtypes支持operator< ,并且具有严格的总sorting和其他sorting语义。

  • 可复制types是复制可构造的,可破坏的,如果x等于yx被复制,则复制也将等于y

  • Iteratortypes必须具有相关的typesvalue_typereferencedifference_typeiterator_category ,它们本身必须满足某些概念。 他们还必须支持operator++并且可以引用。

概念之路

约束是实现C ++完整概念function的第一步。 它们是非常重要的一步,因为它们提供了types的静态可执行的需求,所以我们可以编写更清洁的模板函数和类。 现在我们可以避免std::enable_if及其元编程的朋友的一些困难和丑陋。

但是,约束build议并没有做很多事情:

  1. 它不提供概念定义语言。

  2. 约束不是概念图。 用户不需要特别注明他们的types是否符合某些约束。 他们静态检查使用简单的编译时语言function。

  3. 模板的实现不受其模板参数的限制。 也就是说,如果你的函数模板对一个约束types的对象做任何事情,那么编译器就无法诊断那个对象。 一个全function的概念提案将能够做到这一点。

约束条款的build议是专门devise的,以便在其上面引入完整的概念build议。 运气好的话,这个过渡应该是一个相当顺利的过程。 概念小组正在寻求为C ++ 14(或不久之后的技术报告)引入约束,而完整的概念可能会在C ++ 17的某个时候出现。

最近(3月12日)概念电话会议纪要和讨论logging第2.3节“精简概念简介”是在同一天发布的: http : //isocpp.org/blog/2013/03 / new-paper-n3576-sg8-concepts-teleconference-minutes-2013-03-12-herb-sutter 。

我的2美分:

  1. 概念精简提议并不意味着要对模板实现进行“types检查”。 即,Concepts-lite将确保(概念上)在模板实例化站点处的接口兼容性。 从论文引用:“概念精简版是C + +的扩展,允许使用谓词约束模板参数”。 就是这样。 它没有说模板主体将被检查(孤立)与谓词。 这可能意味着当你谈论概念时,没有什么一stream的概念。 如果我没有记错的话,在概念模糊的提案中,提供的types不能less于也不能多于模板的实现

  2. concepts-lite使用了一些编译器支持的语法技巧来增强constexpr函数。 查找规则没有变化。

  3. 程序员不需要编写概念图。

  4. 最后,再次引用“约束提议并不直接涉及语义的规范或使用;它仅针对语法检查”。 这意味着公理不在范围之内(到目前为止)。