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

时间:2013-03-27 21:11:46

标签: c++ c++11 d c++-concepts

我想知道C ++完整概念提案和模板约束之间的语义差异(例如,Dlang或the new concepts-lite proposal for C++1y中出现的约束)。

什么是能够胜任模板约束的完整概念?

3 个答案:

答案 0 :(得分:132)

  

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

the constraints proposal的第3节以合理的深度涵盖了这一点。

The concepts proposal已被置于后燃烧器上一段时间,希望能够在更短的时间内充实约束(即概念 - 精简版),目前至少在C中实现某些目标++ 14。约束提议旨在平滑过渡到后来的概念定义。约束概念提案的一部分,是其定义中必不可少的构建块。

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

  

概念=约束+公理

快速总结其含义:

  1. 约束 - 对类型的静态可评估属性的谓词。纯粹的语法要求。不是域抽象。
  2. Axioms - 假定为真的类型的语义要求。没有静态检查。
  3. 概念 - 算法对其参数的一般,抽象要求。根据约束和公理来定义。
  4. 因此,如果您将约束(语义属性)添加到约束(语法属性),您将获得概念。


    概念-精简版

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

    约束

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

    让我们看一下行动中的约束:

    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函数中引发了一些可怕的错误,这对任何人都没有意义。

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

    1. 这种类型的操作符是否过载?
    2. 这些类型可以用作此运算符的操作数吗?
    3. 这种类型有这样的特质吗?
    4. 这个常数表达式是否相等? (对于非类型模板参数)
    5. 此类型是否有一个名为yada-yada的函数返回该类型?
    6. 这种类型是否满足所有语法要求?
    7. 但是,约束并不意味着替换类型特征。相反,他们将携手合作。现在可以根据概念和类型特征方面的某些概念来定义某些类型特征。

      实施例

      因此,关于约束的重要一点是它们并不关心语义。约束的一些好例子是:

      • sort:检查类型是否Equality_comparable<T>,两个操作数相同。

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

      • ==:检查类型是否为算术类型。

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

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

      • Input_iterator<T>:检查给定类型是否相同。

      您可以使用特殊concepts-lite build of GCC尝试所有这些。


      Beyond Concepts-Lite

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

      公理

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

      虽然Same<T,U>约束会告诉您有Equality_comparable<T,U>类型operator==T,但它并不能告诉您该操作是什么< EM>装置。为此,我们将有公理U。这个公理说,当这两种类型的对象与给出Equivalence_relation的{​​{1}}进行比较时,这些对象是等价的。这似乎是多余的,但肯定不是。您可以轻松定义operator==,而不是true。你这样做是邪恶的,但你可以。

      另一个例子是operator==公理。说operator<类型的两个对象可以与GreaterT运算符进行比较,这一切都很好,但它们意味着什么>公理说iff <大于Greater,那么x小于y。建议的规范如此公理如下:

      y

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

      1. 这两个运营商之间是否存在这种关系?
      2. 这种类型的运算符是否意味着这个?
      3. 这种类型的操作是否具有这种复杂性?
      4. 该运算符的结果是否意味着这是真的?
      5. 也就是说,他们完全关注这些类型的类型和操作的语义。这些东西无法静态检查。如果需要检查,类型必须以某种方式宣称它遵守这些语义。

        实施例

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

        • 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_equalityx:if y,由复制构造创建的同一类型的新对象T仍然x == y(也就是说,它是非破坏性的)。

        概念

        现在概念很容易定义;它们只是约束和公理的组合。它们提供了对类型的语法和语义的抽象要求。

        例如,请考虑以下T{x} == y概念:

        x == y

        首先请注意,对于模板类型Orderedconcept 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。这是静态检查,因此必须存在。
        • Axioms:对于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类型必须包含自己必须符合某些概念的关联类型xyIteratorvalue_type。他们还必须支持reference并且可以取消引用。

        概念之路

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

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

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

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

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

        4. 约束提案是专门设计的,因此可以在其上引入完整的概念提案。运气好的话,过渡应该是一个相当平稳的过程。概念组正在寻求为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美分:

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

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

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

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