C++20 概念布尔可测试的奥秘

康桓瑋*_*康桓瑋 4 c++ comparison c++-concepts c++20

C++20引入了一个比较概念boolean-testable,但是我注意到它的斜体和中间的连字符,说明它只是为了exposition-only,由于没有所谓的std::boolean_testablein <concepts>,我们自己也不能使用代码。

这个仅用于展示的概念的目的是什么?为什么这个概念如此神秘?

T.C*_*.C. 9

boolean-testable 来自 LWG 反复尝试准确指定类型何时足够“布尔型”以适合用作谓词和比较的结果。

起初,公式只是简单地“转换为bool”,而在 C++11 中“上下文可转换为bool”,但LWG2114指出这是不够的:如果某物的唯一要求是它可以转换为bool,那么您唯一的要求是可以做的是将其转换为bool. 你不能写!pred(x), or i != last && pred(*i),因为!and&&可能会超载去做任何事情。这将需要bool到处都带有显式强制转换的乱码。

图书馆真正的意思是“它bool在我们想要的时候转换”,但事实证明这真的很难表达:我们想要b1 && b2使用内置运算符的短路魔法&&,即使当b1b2是不同的“布尔值” -ish”类型。但是,当b1单独查看 的类型时,我们不知道还有哪些其他“布尔型”类型。孤立地分析类型基本上是不可能的。

然后 Ranges TS 出现了,并试图指定一个Boolean概念。这是一个极其复杂的概念 - 有十多个表达要求 - 仍然无法解决混合类型比较问题,并增加了自己的问题。例如,它需要bool(b1 == b2)等于bool(b1) == bool(b2)and bool(b1 == bool(b2)),这意味着int它不会建模,Boolean除非它仅限于域{0, 1}

随着 C++20 即将发布,这些问题导致P1934R0提出认输:只需要类型来建模convertible_to<bool>,并要求用户bool在需要时将其强制转换。正如P1964R0指出的那样,这有其自身的问题,尤其是现在我们正在为公众消费提供概念:我们真的想强迫用户乱扔他们的代码,这些代码使用标准库概念和强制转换为bool? 特别是如果只有用户九牛一毛使用病理类型的过载&&||反正没有标准库的实现支持这种类型的?

最终结果是boolean-testable,它旨在确保您可以使用!(只需一次 -!!x不需要工作),&&||在谓词/比较的结果上获得正常语义(包括短路&&||)。为了解决混合类型问题,它的规范包含一个复杂的标准语块,讨论名称查找和模板参数推导以及隐式转换序列,但它实际上归结为“不要傻”。P1964R2包含详细的措辞理由。

为什么它只是展览?boolean-testable在 C++20 周期中来得真的很晚:LEWG 周五下午在贝尔法斯特批准了 P1964 的方向(2019 年 11 月的会议,在 C++20 发布之前的一次会议),并且仅拥有一个博览会概念的风险要低得多一个命名的,特别是因为也没有太多的动机将其公开。当然,LEWG 房间里没有人要求说出它的名字。


Sto*_*ica 3

与所有仅供说明的概念一样,其目的是简化标准中的规范。它只是一个构建块,用于指定其他(可能面向用户的)概念,而无需重复概念模型。值得注意的是,它出现在另一个仅供说明的概念的规范中

template<class T, class U>
  concept weakly-equality-comparable-with = // exposition only
    requires(const remove_reference_t<T>& t,
             const remove_reference_t<U>& u) {
      { t == u } -> boolean-testable;
      { t != u } -> boolean-testable;
      { u == t } -> boolean-testable;
      { u != t } -> boolean-testable;
    };
Run Code Online (Sandbox Code Playgroud)

weakly-equality-comparable-with对于使用不一定逐字返回类型重载比较运算符的类型来说,是满足的bool。我们仍然可以使用这些表达式来比较对象,因此该标准旨在对它们进行推理。这不是一个假设,它们可以出现在野外。帕洛阿尔托报告的一个例子:

...一个这样的例子是 QChar 类的早期版本(至少是 1.5 及更早版本)(Nokia Corporation,2011)。

class QChar
{
  friend int operator==(QChar c1, QChar c2);
  friend int operator!=(QChar c1, QChar c2);
};
Run Code Online (Sandbox Code Playgroud)

尽管该运算符不返回布尔值,但我们应该能够在标准算法中使用此类。

至于你的另一个问题

为什么这个概念如此神秘?

事实并非如此。但是,如果仅在 cppreference 上检查它,则可能会错过上下文,因为在那里交叉引用它可能并不容易。