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

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

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

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

最佳答案

The following information is out of date. It needs to be updated according to the latest Concepts Lite draft.



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

The concepts proposal已经暂时搁置了一段时间,希望可以在更短的时间范围内充实和实现约束(即概念精简版),目前至少针对 C++14 中的某些内容。约束提案旨在平滑过渡到稍后的概念定义。约束是概念提案的一部分,是其定义中的必要组成部分。

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

Concepts = Constraints + Axioms



快速总结它们的含义:
  • 约束 - 对类型的静态可评估属性的谓词。纯粹的语法要求。不是领域抽象。
  • 公理 - 假设为真的类型的语义要求。没有静态检查。
  • 概念 - 算法对其参数的一般抽象要求。根据约束和公理定义。

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

    概念精简版

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

    约束

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

    让我们来看看一个正在起作用的约束:

    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 内部抛出一些可怕的错误。对任何人都没有意义的功能。

    约束谓词与类型特征非常相似。它们采用一些模板参数类型,并为您提供有关它的一些信息。约束试图回答以下关于类型的问题:
  • 这种类型是否重载了某某运算符?
  • 这些类型可以用作该运算符的操作数吗?
  • 这种类型有这样那样的特质吗?
  • 这个常量表达式等于那个吗? (对于非类型模板参数)
  • 这种类型是否有一个名为 yada-yada 的函数返回该类型?
  • 这种类型是否满足用作该类型的所有语法要求?

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

    例子

    所以关于约束的重要一点是他们不关心语义。约束的一些很好的例子是:
  • Equality_comparable<T> : 检查类型是否有==具有相同类型的两个操作数。
  • Equality_comparable<T,U> : 检查是否有 ==具有给定类型的左右操作数
  • Arithmetic<T> : 检查类型是否为算术类型。
  • Floating_point<T> : 检查类型是否为浮点类型。
  • Input_iterator<T> : 检查类型是否支持输入迭代器必须支持的语法操作。
  • Same<T,U> : 检查给定的类型是否相同。

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

    超越概念-精简版

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

    公理

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

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

    另一个例子是 Greater公理。说两个 T 类型的对象都很好。可以与>比较和 <运营商,但他们是什么意思? Greater公理说 iff 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 : 对于 xy类型 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< .这是静态检查的,因此它必须存在。
  • 公理:对于 xy类型 T :
  • x < y给出严格的总排序。
  • x大于 y , y小于 x ,反之亦然。
  • x小于或等于 y , y不小于x ,反之亦然。
  • x大于或等于 y , y不大于 x ,反之亦然。

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

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

    例子

    以下是一些概念示例:
  • Regular类型是可构造的、可破坏的、可复制的,并且可以进行比较。
  • Ordered类型支持 operator< ,并具有严格的总排序和其他排序语义。
  • Copyable类型是可复制构造的,可破坏的,如果 x等于 yx被复制,拷贝也将比较等于 y .
  • Iterator类型必须有关联类型 value_type , reference , difference_type , 和 iterator_category它们本身必须满足某些概念。他们还必须支持 operator++并且可以取消引用。

  • 概念之路

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

    但是,约束提案没有做很多事情:
  • 它不提供概念定义语言。
  • 约束不是概念图。用户不需要特别注释他们的类型以满足某些约束。它们是静态检查使用的简单编译时语言功能。
  • 模板的实现不受其模板参数的约束。也就是说,如果您的函数模板对受约束类型的对象执行了不应执行的操作,则编译器无法对此进行诊断。一个功能齐全的概念提案将能够做到这一点。

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

    关于c++ - 概念和模板约束之间有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15669592/

    相关文章:

    C++ 拆分宽字符字符串

    c++ - Pthread 将函数传递给池

    c++ - 此示例中 move 和前进之间的不同

    c++ - std::addressof 是否否定 STL operator& 要求?

    mixins - 使用 foreach 循环——无法读取变量

    c# - 基于ANTLR v3的成熟编译器

    c++ - 使用 C++ 将整数写入二进制文件?

    c++ - 如何在 C++ 中声明原子 vector

    c++ - 如何将 this 的 shared_ptr 返回给拥有它的对象?

    class - 可变方法 X.this 无法使用 D 中的不可变对象(immutable对象)错误进行调用