我想知道C++全概念提案和模板约束(例如D语言中出现的约束条件或C++1y中的新概念轻量级提案)之间的语义差异是什么。
全面的概念能够做到什么,而模板约束不能做到什么?
我想知道C++全概念提案和模板约束(例如D语言中出现的约束条件或C++1y中的新概念轻量级提案)之间的语义差异是什么。
全面的概念能够做到什么,而模板约束不能做到什么?
简单概括它们的含义:概念=约束条件+公理
因此,如果您将公理(语义属性)添加到约束(语法属性)中,则会得到概念。
概念轻量级提案仅提供了第一部分的限制条件,但这是实现完整概念所必需的重要步骤。
限制条件都与语法有关。它们为我们提供了一种在编译时静态区分类型属性的方式,以便我们可以基于其语法属性限制用作模板参数的类型。在当前的限制条件提案中,它们使用命题演算的子集来表示,使用逻辑连接词如&&
和||
。
让我们看一个限制条件的示例:
template <typename Cont>
requires Sortable<Cont>()
void sort(Cont& container);
sort
的函数模板。新添加的内容是requires clause。要求条款对此函数的模板参数施加了一些约束。特别地,该约束表示类型Cont
必须是可排序的类型Sortable
。一个好处是它可以以更简洁的形式编写:template <Sortable Cont>
void sort(Cont& container);
因此,限制条件的重要之处在于它们一点也不关心语义。一些好的示例包括:
Equality_comparable<T>
:检查该类型是否具有使用该相同类型的两个操作数进行==
比较。
Equality_comparable<T,U>
:检查是否存在使用给定类型的左右操作数进行==
比较。
Arithmetic<T>
:检查该类型是否为算术类型。
Floating_point<T>
:检查该类型是否为浮点类型。
Input_iterator<T>
:检查该类型是否支持输入迭代器必须支持的语法操作。
Same<T,U>
:检查给定类型是否相同。
您可以尝试使用特殊的concepts-lite build of GCC进行所有这些操作。
现在我们进入了超越概念-Lite提案的一切。这比未来本身更具有未来感。 从这里开始的一切都很可能会发生很大的变化。
公理与语义学有关。它们指定关系、不变量、复杂性保证和其他类似的事情。让我们看一个例子。
虽然Equality_comparable<T,U>
约束将告诉您存在一个接受类型T
和U
的operator==
,但它并没有告诉您该操作的含义。因此,我们将拥有公理Equivalence_relation
。这个公理说,当这两种类型的对象使用operator==
进行比较且结果为true
时,这些对象是等价的。这可能看起来是多余的,但它绝对不是。您可以轻松地定义一个operator==
,使其表现得像operator<
。你这样做是邪恶的,但你可以这样做。
template<typename T>
axiom Greater(T x, T y) {
(x>y) == (y<x);
}
所以公理回答以下类型的问题:
也就是说,它们完全关注类型和对这些类型的操作的语义。这些事情不能静态检查。如果需要检查这一点,则某种方式必须声明类型遵守这些语义。
以下是一些常见的公理示例:
等价关系
: 如果两个对象比较 ==
,它们是等同的。
大于
: 每当 x > y
,那么 y < x
。
小于等于
: 每当 x <= y
,那么 !(y < x)
。
复制相等性
: 对于类型 T
的 x
和 y
: 如果 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<
。这是静态检查的,所以它必须存在。T
的x
和y
:
x < y
给出了一个严格的全序关系。x
大于y
时,y
小于x
,反之亦然。x
小于或等于y
时,y
不小于x
,反之亦然。x
大于或等于y
时,y
不大于x
,反之亦然。将约束和公理结合起来,就可以得到概念。它们定义了用于算法的抽象类型的语法和语义要求。目前算法必须假设使用的类型将支持某些操作并表达某些语义。通过概念,我们将能够确保满足要求。
在最新的概念设计中,编译器仅检查模板参数是否满足概念的语法要求。公理未经检查。由于公理表示静态无法评估(或往往完全无法检查)的语义,类型的作者必须明确声明其类型满足概念的所有要求。这在以前的设计中被称为概念映射,但现已被删除。Regular
类型是可构造的、可销毁的、可复制的,并且可以进行比较。
Ordered
类型支持 operator<
,并具有严格的总排序和其他排序语义。
Copyable
类型是可复制构造的、可销毁的,如果 x
等于 y
并且对 x
进行复制,则复制也将与 y
相等。
Iterator
类型必须具有关联类型 value_type
、reference
、difference_type
和 iterator_category
,这些类型本身必须满足某些概念。它们还必须支持 operator++
并且可解引用。
约束条件是 C++ 具备完整概念特性的第一步。它们是非常重要的一步,因为它们提供了类型的静态强制要求,使我们能够编写更清晰的模板函数和类。现在我们可以避免一些困难和丑陋的 std::enable_if
及其元编程朋友的问题。
它不提供概念定义语言。
约束不是概念映射。用户不需要将其类型明确注释为满足某些约束。它们是使用简单的编译时语言特性进行静态检查。
模板的实现不受其模板参数的约束限制。也就是说,如果您的函数模板对受限类型的对象执行任何不应该执行的操作,则编译器无法诊断出来。完整的概念提案可以解决这个问题。
约束提案是专门设计的,以便在其基础上引入完整的概念提案。希望这个转换过程会比较顺利。概念小组正在寻求在C++14中引入约束(或在技术报告中很快引入),而完整的概念可能会在C++17左右开始出现。
我的意见:
Concepts-lite提案不是用来对模板实现进行“类型检查”的。即,概念轻量级将确保(理论上)接口在模板实例化位置的兼容性。引用论文:“概念轻量级是C++的一个扩展,允许使用谓词来约束模板参数”。就是这样。它并没有说模板主体将被检查(隔离)与谓词相比。如果我记得正确,这可能意味着当你谈论概念-重度提议时,并没有一流的原型概念。原型概念是指在实现模板时提供满足标准的类型,既不多也不少。
Concepts-lite使用了由编译器支持的具有一些语法技巧的虚荣constexpr函数。查找规则没有改变。
程序员不需要编写概念映射。
最后再次引用:“约束提案并不直接涉及语义的规范或使用;它仅针对语法检查。”这意味着公理不在范围内(到目前为止)。