开发者

c++ order of defs in the class, surprise

Stroustrup states in C++ Language book that order of definitions in the class does not matter.

Indeed:

class C1 { 
       int foo() { return bar(); }    // where is bar() ?
       int bar() { return m_count; }  // oh, here is bar(). but where is m_count ?
       int m_count;                   // here is m_count. Better late than never !
}

This compiles. Despite misordering. As promised. So far, so good.

However, this does not compile:

class C2 {
      void baz(Inner *p) {} // we were promised that order does not matter
                            // is Inner defined ?
      struct Inner {};      // yes, Inner is define here.
};

This looks a contradiction to Stroustrup's promise of free ordering inside the class. Quoting Stroustrup: "A member function declared within a class can r开发者_如何学运维efer to every member of the class as if the class were completely defined before the member function bodies were considered".

Does anybody know a ref to standard clause that allows C1 and disallows C2 ? I am curious why C2 was disallowed while C1 is allowed. Is it compiler bug that contradicts the standard, maybe ?


Note that the following compiles fine (in VS2008):

class C2 {
  void baz() {  Inner* i = new Inner(); }
  struct Inner {}; 
};

There are two differences between your two examples. The first uses an undeclared symbol inside the body of a function and the second uses an undeclared type in the signature of the function.

I suspect that my example and your first example both work because the function bodies aren't resolved until after the entire class declaration has been parsed. The function signatures have to make sense as soon as they are encountered.


An identifier that denotes a type must be declared prior to use. This has to do with the complicated structure of C++ grammar. The compiler simply cannot parse certain code if it does not know beforehand which identifiers are types.


You are confusing "declarations" with "definitions". The inner class must be declared - if only forward declared - before it can be used.


The order of definition does not matter, but the order of declaration does.

In C++, a declaration means (roughly) stating the "kind" or type of a symbol:

  • class A; --> A is of kind "class"
  • void foo(int); --> foo is a function that takes an int and returns nothing

A definition, however, fully defines what the symbol relates to. As in C, a definition happens to be a declaration too.

Finally, to muddy the waters further, for user-declared types, sometimes a definition is required (complete-type) while sometimes a simple declaration is sufficient...

Now, let us revise your issue, I'll illustrate it with a simple example using C++0x:

struct A {
  void foo() { ++count; }
  void bar(decltype(count) c); // error: 'count' was not declared in this scope

  int count;
};

struct B {
  void foo() { Inner a; a.foo(); }
  void bar(Inner& i); // error: 'Inner' has not been declared

  struct Inner { void foo(); };
};

As you can notice, A::foo is parsed correctly, while A::bar is not.

The issue comes from the fact that the compiler "cheats": the methods body are fully analyzed only once the class has been completely parsed. Therefore it is fine to refer to a yet undeclared type/attribute/function in a function body, but it is not fine to refer to it in a function signature (declaration).

You could say that to the compiler, the code is equivalent to:

struct A {
  void foo();
  void bar(decltype(count) c); // error: 'count' was not declared in this scope

  int count;
};
void A::foo() { ++count; }

struct B {
  void foo();
  void bar(Inner& i); // error: 'Inner' has not been declared

  struct Inner { void foo(); };
};
void B::foo() { Inner a; a.foo(); }

Stroustrup sentence is "easy", but not necessarily accurate. For example, using Inner as an attribute requires that it is fully defined (only complete types may be used as non static attributes), which can cause further grief.

struct C {
  struct Inner;

  Inner foo; // error: field 'foo' has incomplete type

  struct Inner { };
};

Though one could argue that Inner foo is a declaration and thus not covered by Stroustrup's quote.


I think the promise of free ordering inside the class is held if you split declaration and definition (into a header and an implementation file). Once you split them, the order really doesn't matter anymore.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜