thb
thb

Reputation: 14464

Declaration after use

The draft C++20 standard N4861 sect. 6.5.1(7) reads:

A name used in the definition of a class X outside of a complete-class context of X shall be declared ... before its use in class X or be a member of a base class of X....

So why does the following compile?

#include <iostream>
  
struct X {
    X(const int i_) : i(i_) {}
    int f() const { return 3*g(); }
    int g() const { return 2*i; }
    const int i;
};

int main()
{
    const X x{7};
    std::cout << x.f() << "\n";
}

I mean, of course, it should indeed compile, and does, and the output is 42 just as one would expect; but I do not understand the standard's phrasing. The standard says, "before its use," but in the example, isn't g() declared after its use? And i, too.

Upvotes: 1

Views: 195

Answers (2)

NathanOliver
NathanOliver

Reputation: 181027

The key part to the paragraph you are quoting is

outside of a complete-class context

Inside a member function body, you are in a complete-class context. This means the rule does not apply.

The full definition for a complete-class contect can be found in [class.mem.general]/7:

A complete-class context of a class (template) is a

  • function body ([dcl.fct.def.general]),
  • default argument ([dcl.fct.default]),
  • default template argument ([temp.param]), noexcept-specifier ([except.spec]), or
  • default member initializer

Upvotes: 4

sweenish
sweenish

Reputation: 5202

The short answer is that you're not breaking the rule cited.

To my understanding, the key part is "outside of a complete-class context." I see that you use g() in f(), and g() had not formally been declared yet, but it's in the class X. If g() were a global function declared and implemented after X, I think that's where you'd run into an issue. If class X had a member Y object, the compiler needs to know all about Y first so that it can be included. That's what the rule is saying.

Upvotes: 1

Related Questions