【发布时间】:2021-04-04 06:06:48
【问题描述】:
C++20引入了一个比较概念boolean-testable,但是我注意到它的斜体和中间的连字符,表示它只是为了说明,因为@987654323中没有所谓的std::boolean_testable @,我们不能在我们自己的代码中使用它。
这个仅用于展示概念的目的是什么?为什么这个概念如此神秘?
【问题讨论】:
标签: c++ comparison c++20 c++-concepts
C++20引入了一个比较概念boolean-testable,但是我注意到它的斜体和中间的连字符,表示它只是为了说明,因为@987654323中没有所谓的std::boolean_testable @,我们不能在我们自己的代码中使用它。
这个仅用于展示概念的目的是什么?为什么这个概念如此神秘?
【问题讨论】:
标签: c++ comparison c++20 c++-concepts
boolean-testable 来自 LWG 反复尝试准确指定类型何时足够“布尔型”以适合用作谓词和比较的结果。
起初,公式只是“可转换为bool”,而在 C++11 中“可上下文转换为bool”,但LWG2114 指出这是不够的:如果对某事的唯一要求是它可以转换为bool,那么您唯一能做的就是将其转换为bool。你不能写!pred(x) 或i != last && pred(*i),因为! 和&& 可能会被超载来做任何事情。这将需要到处乱扔带有明确bool 强制转换的代码。
该库的真正含义是“当我们想要它时它会转换为 bool”,但事实证明这真的很难表达:我们希望 b1 && b2 参与短- 内置运算符&& 的电路魔法,即使b1 和b2 是不同的“布尔-ish”类型。但是,当单独查看 b1 的类型时,我们不知道可能还有哪些其他“布尔型”类型。孤立地分析类型基本上是不可能的。
然后 Ranges TS 出现了,并随之尝试specify a Boolean concept。这是一个非常复杂的概念 - 有十几个表达式要求 - 仍然无法解决混合类型比较问题,并添加了自己的问题。例如,它要求bool(b1 == b2) 等于bool(b1) == bool(b2) 和bool(b1 == bool(b2)),这意味着int 不会模拟Boolean,除非它被限制在域{0, 1}。
随着 C++20 即将发布,这些问题导致 P1934R0 提出认输:只需要将类型建模为 convertible_to<bool>,并要求用户在需要时将其转换为 bool。正如P1964R0 所指出的那样,这有其自身的问题,特别是现在我们正在为公共消费提供概念:我们真的想强迫用户乱扔他们的代码,这些代码使用标准库概念和bool 进行强制转换吗?尤其是如果只有极少数的用户使用重载 && 和 || 的病态类型,并且没有标准库实现支持这些类型?
最终的结果是boolean-testable,这是为了保证你可以使用!(只需一次——!!x不需要工作)、&&和@987654358 @ 在谓词/比较的结果上并获得正常语义(包括 && 和 || 的短路)。为了解决混合类型问题,它的规范包含一个复杂的标准术语,讨论名称查找和模板参数推导和隐式转换序列,但它真的归结为“不要愚蠢”。 P1964R2 包含详细的措辞理由。
为什么它只是展览? boolean-testable 在 C++20 周期中来得很晚:LEWG 周五下午在贝尔法斯特批准了 P1964 的方向(2019 年 11 月的会议,C++20 发布之前的一次会议),而且很多与命名概念相比,仅展示概念的风险更低,特别是因为也没有太多将其公开的动机。当然,LEWG 房间里没有人要求为其命名。
【讨论】:
与所有仅用于说明的概念一样,其目的是简化标准中的规范。它只是用于指定其他(可能面向用户的)概念的构建块,而无需重复概念模型。值得注意的是,它出现在another exposition-only concept的规范中
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;
};
weakly-equality-comparable-with 对于重载比较运算符的类型满足,返回类型不一定是逐字的bool。我们仍然可以使用这些表达式来比较对象,因此标准试图对它们进行推理。这不是假设,它们可以出现在野外。来自Palo Alto report 的示例:
... 一个这样的例子是 QChar 类的早期版本(至少 1.5 和更早版本)(诺基亚公司,2011 年)。
class QChar { friend int operator==(QChar c1, QChar c2); friend int operator!=(QChar c1, QChar c2); };我们应该能够在我们的标准算法中使用这个类,尽管运算符不返回布尔值。
至于你的其他问题
为什么这个概念如此神秘?
不是。但是,如果仅在 cppreference 上对其进行检查,则可能会错过上下文,因为在那里交叉引用它可能并不容易。
【讨论】:
convertible_to<bool>。它对标准库使用的类型进行了一些特定的推理,这些类型可能会发生变化。由于概念如此(相对)新,我相信不公开这些实施细节是明智的。就它有用而言,您是否阅读过它的确切定义?它在用户代码中的用处对我来说并不明显,但也许你有一个我想不出的用例。
您可以使用std::_Boolean_testable<T>
【讨论】: