来自空大括号的模糊复制赋值的编译器差异

我一直在试图理解std::nullopt_t不允许DefaultConstructible在 C++17(引入它的地方)及更高版本中的基本原理,并在此过程中解决了一些编译器差异混淆。

考虑以下违反规范的(它是DefaultConstructible)实现nullopt_t

struct nullopt_t {
    explicit constexpr nullopt_t() = default;
};

它是 C++11 和 C++14(无用户提供的构造函数)中的聚合,但不是 C++17(构造函数explicit)和 C++20(用户声明的构造函数)中的聚合。

现在考虑以下示例:

struct S {
    constexpr S() {}
    S(S const&) {}
    S& operator=(S const&) { return *this; }   // #1
    S& operator=(nullopt_t) { return *this; }  // #2
};

int main() {
    S s{};
    s = {};  // GCC error: ambiguous overload for 'operator=' (#1 and #2)
}

这在 C++11 到 C++20 中被 GCC(各种版本,比如 v11.0)拒绝,但在 C++11 到 C++11 中被 Clang(比如 v12.0)和 MSVC(v19.28)接受C++20。

演示

我最初的假设是该程序:

  • 在 C++11 和 C++14 中格式错误,因为nullopt_t(如上)是一个聚合,而它
  • 是公形成式C ++ 17和C ++ 20,因为它不再是一种聚集体,这意味着它的显式默认的构造应该禁止的临时副本列表-INITnullopt_t根据需要用于在拷贝赋值运算符对象#2是可行的,

但是没有一个编译器完全同意这个理论,有些我可能遗漏了一些东西。

什么编译器在这里是正确的(如果有的话),我们如何通过相关的标准部分(和 D​​R:s,如果相关)来解释它?

以上是来自空大括号的模糊复制赋值的编译器差异的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>