When is complete-class scope really useful in default arguments, default member initializers and exception specification?

Viewed 60

The standard says that default arguments, class member default initializers and method exception specifications should be parsed in a complete-class context; that is, the class should be regarded as complete within those expressions or specifiers. Naturally, it follows that all the names defined in the scope of the class should be visible to those expressions, even the names declared/defined after the expression:

struct Test
{
    // Well-formed, `bar` is looked up in complete-class context:
    static void foo() noexcept(noexcept(bar()));

    static void bar() noexcept;
};

I imagine, this requirement puts a lot of burden on the compilers: they have little choice but to postpone the parsing of those expressions to until the class definition is complete (or even further, in case of nested classes), which leads to other problems and pitfalls.

Which is why I can't help wondering: Why? What good does it do?
Isn't it always possible to reorder the member declarations in such a way that a name is always declared before it is used (by before I mean up the source text flow).

Could you come up with an example which cannot be reordered, so that a default argument, a default initializer and an exception specification clearly must be parsed in the complete-class context?

1 Answers

Counter example:

struct Test
{
    // Well-formed, `bar` is looked up in complete-class context:
    static void foo() noexcept(noexcept(bar()));

    static decltype(foo()) bar() noexcept;
};

It maybe not a realistic example (I could explicity write void instead), but disallowing such mutual dependency would be a major restriction that would be unnecessary, because compilers can handle code like the above.

Different example that is maybe more addressing your question:

struct Test
{
    // Well-formed, `bar` is looked up in complete-class context:
    static void foo() noexcept(noexcept(bar()));

    static void bar(decltype(foo) f = foo) noexcept;
};
Related