这会产生一个错误:
template <class T, T A, T B>
requires A > B // <-- error
class X{};
错误:在requires中,此表达式周围需要括号条款
requires A < B ~~^~~ ( )
几乎所有运算符都给出此错误(requires A > B
、requires A == B
、requires A & B
、requires !A
(
然而&&
和||
似乎起作用:
template <class T, T A, T B>
requires A && B // <-- ok
class X{};
在godbolt上用gcc主干和clang主干进行测试(2020年5月(。两个编译器都给出了相同的结果
要求子句使用特殊的表达式语法来避免某些病态的解析歧义。正如cppreference上所指出的,允许的形式是
- 一个主表达式
- 与运算符
&&
连接的一系列主表达式 - 与运算符CCD_ 8连接的上述表达式的序列
是的,&&
和||
在这里被特殊处理,因为约束知道连接和析取。
§13.5.1限制[临时施工]
约束是一系列逻辑运算和操作数,用于指定模板参数的要求。的操作数逻辑运算是约束。有三种不同的约束:
(1.1(-连词(13.5.1.1(,
(1.2(-析取(13.5.1.1(和
(1.3(-原子约束(13.5.1.2(。
它们需要通过约束来定义偏序。
13.5.4按约束的部分排序[temp.constr.order]
[注意:[…]此偏序用于确定
- (2.1(非模板函数的最佳可行候选者(12.4.3(
- (2.2(非模板函数(12.5(的地址
- (2.3(模板-模板自变量的匹配(13.4.3(
- (2.4(类模板专业化的偏序(13.7.5.2(,以及
- (2.5(函数的偏序模板(13.7.6.2(
-尾注]
使此代码工作的原因:
template <class It>
concept bidirectional_iterator = requires /*...*/;
template <class It>
concept randomaccess_iterator = bidirectional_iterator<It> && requires /*...*/;
template <bidirectional_iterator It>
void sort(It begin, It end); // #1
template <randomaccess_iterator It>
void sort(It begin, It end); // #2
std::list<int> l{};
sort(l.begin(), l.end()); // #A -> calls #1
std::vector<int> v{};
sort(v.begin(), v.end()); // #B -> calls #2
但是对于呼叫#B
,即使两个sort
都是可行的,因为这两个约束(满足randomaccess_iterator
和bidirectional_iterator
(,sort #2
(具有randomaccess_iterator
的那个(也被正确地选择,因为它比sort #1
(具有bidirectional_iterator
的那个(更受约束,因为randomaccess_iterator
包含bidirectional_iterator
:
请参阅如何使用概念选择最佳约束函数模板?