Ray*_*ery 95 c++ d c++11 c++-concepts
我想知道C++完整概念提议和模板约束之间的语义差异(例如,Dlang中出现的约束或C++ 1y的新概念 - 精简提议).
什么是能够比模板约束做的完整概念不能做到的?
Jos*_*eld 133
以下信息已过期.它需要根据最新的Concepts Lite草案进行更新.
约束提案的第3节以合理的深度涵盖了这一点.
这个概念提议已经被搁置在后面燃烧器上一小段时间,希望能够在更短的时间内充实和实现约束(即概念 - 精简版),目前至少在C++ 14中有针对性.约束提议旨在平滑过渡到后来的概念定义.约束是概念提议的一部分,是其定义中必不可少的构建块.
在C++概念库设计中,Sutton和Stroustrup考虑以下关系:
概念=约束+公理
快速总结一下它们的含义:
因此,如果将公理(语义属性)添加到约束(语法属性),则可以获得概念.
概念 - 精简提案只给我们带来了第一部分,即约束,但这是迈向完全成熟概念的重要而必要的步骤.
约束都是关于语法的.它们为我们提供了一种在编译时静态识别类型属性的方法,以便我们可以根据语法属性限制用作模板参数的类型.在当前的约束提议中,它们使用类似&&
和的逻辑连接词用命题演算的子集表达||
.
我们来看一下行动中的约束:
template <typename Cont>
requires Sortable<Cont>()
void sort(Cont& container);
Run Code Online (Sandbox Code Playgroud)
这里我们定义一个名为的函数模板sort
.新增加的是要求条款.requires子句为此函数的模板参数提供了一些约束.特别是,此约束表示类型Cont
必须是Sortable
类型.一个巧妙的事情是它可以用更简洁的形式写成:
template <Sortable Cont>
void sort(Cont& container);
Run Code Online (Sandbox Code Playgroud)
现在,如果您尝试传递任何不考虑Sortable
此函数的内容,您将收到一个很好的错误,它会立即告诉您推导出的类型T
不是Sortable
类型.如果你在C++ 11做到了这一点,你不得不从投入了一些可怕错误里面的sort
那个没有意义的任何功能.
约束谓词与类型特征非常相似.他们采用一些模板参数类型,并为您提供一些信息.约束试图回答以下关于类型的问题:
但是,约束并不意味着取代类型特征.相反,他们将携手合作.现在可以根据概念和类型特征方面的某些概念来定义某些类型特征.
所以关于约束的重要一点是它们并不关心语义.一些好的约束例子是:
Equality_comparable<T>
:检查类型是否==
包含两个相同类型的操作数.
Equality_comparable<T,U>
:检查是否存在==
给定类型的左右操作数
Arithmetic<T>
:检查类型是否为算术类型.
Floating_point<T>
:检查类型是否为浮点类型.
Input_iterator<T>
:检查类型是否支持输入迭代器必须支持的语法操作.
Same<T,U>
:检查给定类型是否相同.
现在我们进入概念 - 精简提案之外的一切.这比未来本身更具未来感.从现在开始的一切都可能会发生很大的变化.
公理都是关于语义的.它们指定了关系,不变量,复杂性保证和其他类似的东西.我们来看一个例子.
虽然Equality_comparable<T,U>
约束会告诉你,有一个operator==
是接受类型T
和U
,它不会告诉你这是什么操作手段.为此,我们将有公理Equivalence_relation
.这个公理说,当这两种类型的物体与operator==
给予比较时true
,这些物体是等价的.这似乎是多余的,但肯定不是.你可以很容易地定义一个operator==
表现得像一个operator<
.你这样做是邪恶的,但你可以.
另一个例子是Greater
公理.说两个类型的对象T
可以>
和<
运算符进行比较,这一切都很好,但它们意味着什么?该Greater
公理说,当且仅当x
是大于y
,则y
是小于x
.建议的规范如此公理如下:
template<typename T>
axiom Greater(T x, T y) {
(x>y) == (y<x);
}
Run Code Online (Sandbox Code Playgroud)
因此,公理回答了以下类型的问题:
也就是说,他们完全关注这些类型的类型和操作的语义.这些东西无法静态检查.如果需要检查,类型必须以某种方式宣称它遵守这些语义.
以下是公理的一些常见例子:
Equivalence_relation
:如果比较两个对象==
,它们是等价的.
Greater
:无论何时x > y
,然后y < x
.
Less_equal
:无论何时x <= y
,然后!(y < x)
.
Copy_equality
:For x
和y
of 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>;
}
Run Code Online (Sandbox Code Playgroud)
首先要注意的模板类型T
是Ordered
,它也必须满足的要求Regular
概念.该Regular
概念是一种非常基本的要求,该类型表现良好 - 可以构建,销毁,复制和比较.
除了这些要求之外Ordered
,T
满足一个约束和四个公理的要求:
Ordered
类型必须有operator<
.这是静态检查,因此必须存在.x
和y
类型T
:
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的某个时候开始出现.
Her*_*ter 22
又见最近的第2.3节"什么是'精简版’相关的概念精简版"(3月12日)概念邮电分钟的讨论记录,它被张贴在这里的同一天:http://isocpp.org/blog/2013/03/new-paper-n3576-sg8-concepts-teleconference-minutes-2013-03-12-herb-sutter.