On Thu, Dec 14, 2023, 9:39 PM Jason McKesson via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Thu, Dec 14, 2023 at 8:03 PM Brian Bi via Std-Proposals
<std-proposals@lists.isocpp.org> wrote:
> Under the current specification of `std::nullopt_t`, it is unspecified whether certain attempts to construct `std::optional<T>` from nested braced lists are well-formed, for example:
> #include <optional>
> struct S1 {
>     S1() = default;
> };
> struct S2 {
>     S2(S1) {}
> };
> std::optional<S2> os{{{}}};
> With libstdc++, this actually selects the `std::nullopt_t` overload of the `std::optional<S2>` constructor, which is then ill-formed because the constructor of `std::nullopt_t` is explicit.

That a bug in libstdc++. Clang and MSVC don't have a problem:

The C++20 standard states that "Type nullopt_t shall not have a
default constructor or an initializer-list constructor, and shall not
be an aggregate." That means that no amount of curly braces should be
able to create one. It's likely that they didn't quite define
`nullopt_t` correctly; pre-C++20 aggregate changes, you have to do
quite a lot of defensive coding to meet those requirements.

List-initialization can call a non-initializer-list constructor, so nothing in the wording implies that libstdc++ is non-conforming. If you look at libstdc++'s definition of `std::nullopt_t` you'll see why it behaves the way it does.