See LWG 2510, "Tag types should not be DefaultConstructible": https://cplusplus.github.io/LWG/issue2510 WG21 seems convinced that there's also a core-language issue here: https://cplusplus.github.io/CWG/issues/1518.html In the notes for LWG2510, I see: > JW [i.e. jwakely] explains that it's important that tag types cannot be constructed from "{}" (e.g. the allocator tag in the tuple constructors). However, it looks like GCC+libstdc++ violates LWG2510 by allowing tag types to be constructible from `{}` (or at least to fail in a SFINAE-unfriendly way). // https://godbolt.org/z/cMzar8Ehf struct Widget { int i[1]; }; std::optional<Widget> r1( {{}} ); // Bug 1: GCC complains about nullopt_t's explicit ctor std::optional<Widget> r2{ {} }; // Bug 2: GCC complains about in_place_t's explicit ctor Now, according to Clang+libstdc++, Clang+libc++, and MSVC+STL, both examples should be well-formed, and should mean: - r1 is direct-initialized from {{}} i.e. a Widget with one element {} i.e. a value-initialized array of int[1]. - r2 is direct-list-initialized from {} i.e. a value-initialized Widget. In the April 2024 WG21 mailing, Brian Bi brings a paper P3112 "Specify Constructor of std::nullopt_t" motivated by this bad behavior of GCC's, https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3112r0.html but really I think it should just be a bug report, since GCC is the one compiler currently misbehaving, and jwakely was already quoted above as wanting `{}` _not_ to construct a tag type. I don't much care whether this is treated as a GCC compiler bug or a libstdc++ library bug, but at first glance it _looks_ like a compiler bug (since libstdc++ works fine with Clang). If it _is_ treated as a libstdc++ bug, you might take this opportunity to audit all of the tag types in the entire library and just make sure they're all implemented using the same consistent technique, whatever it is.
Standalone testcase: struct nullopt_t { enum class Hidden { Token }; explicit constexpr nullopt_t(Hidden) noexcept { } }; struct in_place_t { explicit constexpr in_place_t() = default; }; template<typename T> struct optional { template<typename U = T> optional(U&&) { } optional(in_place_t); optional(nullopt_t); }; struct Widget { int i[1]; }; optional<Widget> r1( {{}} ); optional<Widget> r2{ {} };
Might be related to Bug 113300 and/or Bug 102257
Dup of Bug 102257, which might be what CWG 2586 says should happen, sadly. *** This bug has been marked as a duplicate of bug 102257 ***
(In reply to Jonathan Wakely from comment #3) > Dup of Bug 102257, which might be what CWG 2586 says should happen, sadly. Oops 2856