什么时候requires子句表达式需要加括号?(双关语纯属偶然)



这会产生一个错误:

template <class T, T A, T B>
requires A > B             // <-- error
class X{};

错误:在requires中,此表达式周围需要括号条款

requires A < B
~~^~~
(    )

几乎所有运算符都给出此错误(requires A > Brequires A == Brequires A & Brequires !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.1(-连词(13.5.1.1(,
    (1.2(-析取(13.5.1.1(和
    (1.3(-原子约束(13.5.1.2(。

它们需要通过约束来定义偏序。

13.5.4按约束的部分排序[temp.constr.order]

  1. [注意:[…]此偏序用于确定

    • (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_iteratorbidirectional_iterator(,sort #2(具有randomaccess_iterator的那个(也被正确地选择,因为它比sort #1(具有bidirectional_iterator的那个(更受约束,因为randomaccess_iterator包含bidirectional_iterator:

请参阅如何使用概念选择最佳约束函数模板?

最新更新