Question Details

No question body available.

Tags

c++ c++23

Answers (1)

February 11, 2026 Score: 9 Rep: 103,235 Quality: High Completeness: 80%

Each class is handled in two passes. The second pass handles function bodies (and is called the "complete-class context"), which is why they can use class members declared below themselves.

When classes are nested, the first pass is done over the outer class and all subclasses, and then similarly the second pass.

Default member initializers are evaluated in the second pass, but your first staticassert() is handled in the first pass, so the initializers weren't seen yet at that point.

So the first assert ends up checking std::isconstructiblev somewhere deep in weaklyincrementable, sees it as false (see below), and this value is then memoized. When you then query it again after the class, you get the old value.

The reason why the member initializers need to be seen for this check isn't obvious, because no matter what they are, they can't stop the class from being default-constructible.

It has something to do with noexceptness of the default constructor (which can't be determined until the initializers are seen). If you explicitly specify the noexceptness of this constructor, the issue disappears:

// One of:
iterator() noexcept = default;
iterator() noexcept(false) = default; // This works too!

The only remaning question is why do we need to know the noexceptness to check isdefault_constructible.