Date
2024-10-15.00:00:00
Message id
14443

Content

The current wording for `std::atomic`'s default constructor in [atomics.types.operations] specifies:

constexpr atomic() noexcept(is_nothrow_default_constructible_v<T>);

Mandates: is_default_constructible_v<T> is true.

This wording has been added by P0883R2 for C++20, which changed `std::atomic`'s default constructor to always value-initialize. Before, the behavior of this constructor was not well specified (this was LWG issue 2334).

The usage of a Mandates element in the specification has as a consequence that std::atomic<T> is always default constructible, even when T is not. For instance:

// not default constructible:
struct NDC { NDC(int) {} };

static_assert(std::is_default_constructible<std::atomic<NDC>>); // OK

The above check is OK as per language rules, but this is user-hostile: actually using std::atomic<NDC>'s default constructor results in an error, despite the detection saying otherwise.

Given that std::atomic<T> already requires T to be complete anyhow ([atomics.types.generic.general] checks for various type properties which require completeness) it would be more appropriate to use a constraint instead, so that std::atomic<T> is default constructible if and only if T also is.