C++ 变体转换构造函数与 bool

C++ variant converting constructor with bool

关于cppreference(4)转换构造函数说明如下:

Converting constructor. Constructs a variant holding the alternative type T_j that would be selected by overload resolution for the expression F(std::forward<T>(t)) if there was an overload of imaginary function F(T_i) for every T_i from Types... in scope at the same time, except that:

  • An overload F(T_i) is only considered if the declaration T_i x[] = { std::forward<T>(t) }; is valid for some invented variable x;
  • If T_i is (possibly cv-qualified) bool, F(T_i) is only considered if std:remove_cvref_t<T> is also bool.

我对关于 bool 的第二个要点特别感兴趣。在示例中,它说:

std::variant<std::string, bool> y("abc"); // OK, chooses string; bool is not a candidate

我现在已经用 clang 7.0.0 (godbolt), gcc.8.2 (godbolt) 和 VS2017 测试了相同的代码。我想知道为什么包含的替代类型是 bool(对于所有三个编译器)而不是 cppreference 描述的 std::string。这是所有三个编译器的标准库中的错误吗?

我还找到了以下文档:P0608R3。这是否意味着 cppreference 列出的修改(两个要点)仅被提议但尚未成为官方标准的一部分?

P0608R3 was adopted in San Diego. Its wording was applied to the working draft - you can see the new wording in [variant.ctor]/12.

作为该变化的一部分,激励示例:

variant<string, bool> x = "abc";

现在包含 string(在 c++20 中),而它曾经包含 bool(在 c++17 中)。此示例的含义在标准版本之间有所不同。

只是 none 的标准库已经实现了这个改变。 非常 最近。它在两个 libstdc++ and libc++ 页面中都被列为不完整。但正如您所见,还有大量 C++20 功能尚未实现。好消息是,现在还是 2019 年初,还有很多时间。

每个版本的 C++ 标准都有错误。数百个。

C++ 实现的目标是有用,因此它们不会盲目地遵守已发布的标准文本。没有理由用一张纸来维护错误对错误的兼容性。

(作为一个极端的例子,在 C++17 之前,标准在技术上要求 std::vector<int> v; 中的 <int> 被解析为 header-name然后被拒绝,因为它不在 #include 指令中。不用说 no 编译器会这样做。)

Cppreference 也旨在提供有用的信息。因此,我们也不维护与标准的 bug-for-bug 兼容性。当一段文字首次出现在 ISO 发表的一篇论文中是没有用的(除了标准的历史学家,也许);作为程序员,我们关心的是当我们使用 -std=c++17 或您的实现的等效标志时我们得到了什么。因此,我们的文档是针对每个 C++ 标准的假设完整且正确的实现以及适用于该标准的所有后续错误修复和说明。* 我们使用当前的实现作为此类证据一个假设的实现就可以了。

没有 特定变更的当前实施时,我们评估变更的性质以预测实施将如何处理它。旨在追溯的核心语言更改被标记为缺陷报告,这使得调用更容易(尽管有时它们不会一直返回,并且 that 不在标签中)。然而,库的更改并没有始终如一地应用 "DR" 标签,所以这个决定更多地取决于我们。

在这种特殊情况下,虽然 P0608 没有被标记为缺陷报告,但它在发布后不久就纠正了 C++17 中一个极其可疑的行为。此外,非常不希望像 std::variant<std::string, bool> x = "abcd"; 这样的代码根据标准模式在同一实现 上默默地改变含义 。依赖于 std::variant 的代码在野外也不常见(这部分是委员会甚至首先批准 "breaking" 更改的部分原因)。结果,我预测这篇论文最终会被追溯应用并相应地记录下来。


*这是几年前理念的改变;因此,我们仍然有很多情况,错误修复在文档中没有被视为具有追溯性,但应该被视为具有追溯性。随着时间的推移,它们正在慢慢清理。