99

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

什么是成熟的概念能够比模板约束不能做的?

4

3 回答 3

139

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

约束提案的第 3 节对此进行了合理深入的讨论。

概念提案被搁置了一段时间,希望约束(即概念精简版)可以在更短的时间范围内充实和实施,目前的目标是至少在 C++14 中有所作为。约束提议旨在平滑过渡到后来的概念定义。约束是概念提案的一部分,并且是其定义中的必要组成部分。

Design of Concept Libraries for C++中,Sutton 和 Stroustrup 考虑了以下关系:

概念 = 约束 + 公理

快速总结它们的含义:

  1. 约束 - 一种类型的静态可评估属性的谓词。纯粹的语法要求。不是领域抽象。
  2. 公理 - 假定为真的类型的语义要求。没有静态检查。
  3. 概念 - 算法对其论点的一般抽象要求。根据约束和公理定义。

因此,如果您将公理(语义属性)添加到约束(句法属性),您就会得到概念。


概念-精简版

精简概念提案只为我们带来了第一部分,即约束,但这是迈向成熟概念的重要且必要的一步。

约束

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

让我们看一下约束的作用:

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

在这里,我们定义了一个名为sort. 新增内容是requires 子句。requires 子句对该函数的模板参数给出了一些约束。特别是,此约束表示类型Cont必须是Sortable类型。一个整洁的事情是它可以写​​成更简洁的形式:

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

现在,如果您尝试将任何不考虑的内容传递Sortable给此函数,您将收到一个很好的错误,立即告诉您推导的类型T不是Sortable类型。如果您在 C++11 中执行此操作,您会从函数内部sort抛出一些对任何人都没有意义的可怕错误。

约束谓词与类型特征非常相似。它们采用一些模板参数类型并为您提供一些有关它的信息。约束试图回答以下关于类型的问题:

  1. 这种类型是否有这样那样的运算符重载?
  2. 这些类型可以用作此运算符的操作数吗?
  3. 这种类型有这样那样的特征吗?
  4. 这个常量表达式等于那个吗?(对于非类型模板参数)
  5. 这种类型是否有一个名为 yada-yada 的函数返回该类型?
  6. 这种类型是否满足所有的语法要求?

然而,约束并不意味着取代类型特征。相反,他们将携手合作。现在可以根据概念定义一些类型特征,而根据类型特征定义一些概念。

例子

所以关于约束的重要一点是,它们一点也不关心语义。约束的一些很好的例子是:

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

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

  • Arithmetic<T>: 检查类型是否为算术类型。

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

  • Input_iterator<T>:检查类型是否支持输入迭代器必须支持的语法操作。

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

您可以使用GCC 的特殊概念精简版来尝试所有这些。


Beyond Concepts-精简版

现在我们进入概念精简版提案之外的所有内容。这比未来本身更具未来感。从现在开始,一切都可能发生很大变化。

公理

公理都是关于语义的。它们指定关系、不变量、复杂性保证和其他类似的东西。让我们看一个例子。

虽然Equality_comparable<T,U>约束会告诉你有一个operator== 接受类型T和的U,但它不会告诉你这个操作意味着什么。为此,我们将有公理Equivalence_relation。这个公理说,当这两种类型的对象与operator==给与比较时true,这些对象是等价的。这似乎是多余的,但肯定不是。您可以轻松地定义一个operator==,而不是表现得像一个operator<. 你这样做是邪恶的,但你可以。

另一个例子是Greater公理。说两个类型的对象T可以与><运算符进行比较,这很好,但它们是什么意思Greater公理说 iffx大于,yy小于x。提议的规范这样的公理看起来像:

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

所以公理回答了以下类型的问题:

  1. 这两个运营商之间有这种关系吗?
  2. 某某类型的这个操作符是这个意思吗?
  3. 对该类型的此操作是否具有这种复杂性?
  4. 该运算符的这个结果是否暗示这是真的?

也就是说,它们完全关注类型的语义和对这些类型的操作。这些东西不能静态检查。如果需要对此进行检查,则类型必须以某种方式声明它遵守这些语义。

例子

以下是一些常见的公理示例:

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

  • Greater: 无论何时x > y,那么y < x

  • Less_equal: 无论何时x <= y,那么!(y < x)

  • Copy_equality: for xand yof type T: if 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概念是一个非常基本的要求,即类型是行为良好的——它可以被构造、销毁、复制和比较。

除了这些要求之外OrderedT满足一个约束和四个公理的要求:

  • 约束:一个Ordered类型必须有一个operator<. 这是静态检查的,因此它必须存在。
  • 公理:对于xy类型T
    • x < y给出严格的总排序。
    • x大于时yy小于x,反之亦然。
    • x小于或等于 时yy不小于x,反之亦然。
    • x大于或等于 时yy不大于x,反之亦然。

像这样结合约束和公理可以为您提供概念。它们定义了用于算法的抽象类型的句法和语义要求。当前的算法必须假设所使用的类型将支持某些操作并表达某些语义。有了概念,我们将能够确保满足要求。

最新的概念设计中,编译器只会检查模板参数是否满足概念的句法要求。公理没有被检查。由于公理表示不可静态评估(或通常无法完全检查)的语义,因此类型的作者必须明确声明其类型满足概念的所有要求。这在以前的设计中被称为概念图,但后来被删除了。

例子

以下是一些概念示例:

  • Regular类型是可构造的、可破坏的、可复制的和可比较的。

  • Ordered类型支持operator<,并具有严格的总排序和其他排序语义。

  • Copyable类型是可复制的,可破坏的,如果x等于y并被x复制,则该副本也将比较等于y

  • Iterator类型必须具有关联的类型value_typereferencedifference_type,并且iterator_category它们本身必须满足某些概念。它们还必须支持operator++并且可以取消引用。

概念之路

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

但是,约束提案没有做的事情有很多:

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

  2. 约束不是概念图。用户不需要专门注释他们的类型以满足某些约束。它们使用简单的编译时语言功能进行静态检查。

  3. 模板的实现不受其模板参数的约束。也就是说,如果您的函数模板对受约束类型的对象做了不应该做的任何事情,编译器就无法诊断。一个功能齐全的概念提案将能够做到这一点。

约束提案经过专门设计,因此可以在其之上引入完整的概念提案。运气好的话,这种过渡应该是相当顺利的。概念组正在寻求为 C++14 引入约束(或在不久之后的技术报告中),而完整的概念可能会在 C++17 前后的某个时候开始出现。

于 2013-03-27T23:13:35.577 回答
22

另请参阅最近(3 月 12 日)Concepts telecon 会议纪要和讨论记录的第 2.3 节中的“concepts lite 的“精简”是什么”,这些记录于同一天发布在此处:http: //isocpp.org/blog/2013/03 /new-paper-n3576-sg8-concepts-teleconference-minutes-2013-03-12-herb-sutter

于 2013-03-28T23:03:34.167 回答
4

我的 2 美分:

  1. 精简概念提案并不意味着对模板实现进行“类型检查” 。即,Concepts-lite 将确保(名义上)模板实例化站点的接口兼容性。从论文中引用:“concepts lite 是 C++ 的扩展,它允许使用谓词来约束模板参数”。就是这样。它并没有说将根据谓词(孤立地)检查模板主体。这可能意味着当您谈论概念精简版时,没有一流的原型概念。如果我没记错的话,archtypes 在概念繁重的提案中是提供不少或不多的类型来满足模板的实现

  2. 概念精简版使用美化的 constexpr 函数和编译器支持的一些语法技巧。查找规则没有变化。

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

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

于 2013-03-28T23:50:14.740 回答