In C++, why does the following compile:
struct test {
void foo() { this->bar++; }
int bar;
};
But not the following:
void foo() { bar++; }
int bar;
To be clear, I do understand that in the second case foo lacks a forward declaration of bar and does not compile. I however do not understand why the first one does not fail for the same reason.
In case of a structure, scope of the member variable is available within the structure. So if you define a function within a structure that variable will be available within the function.
But that is the not the case in second scenario.
Related
I have been programming in C++ for quite some time and I never thought about this until today.
Consider the following code:
struct foo
{
// compiles fine
void bar()
{
a = 1;
my_int_type b;
b = 5;
}
// Just a declaration, this fails to compile, which leads me to assume that
// even though the bar() method is declared and defined all at once, the
// compiler looks/checks-syntax-of the class interface first, and then compiles
// the respective definitions...?
void bar2(my_int_type); // COMPILE ERROR
my_int_type b; // COMPILE ERROR because it comes before the typedef declaration
typedef int my_int_type;
my_int_type a;
void bar3(my_int_type); // compiles fine
};
int main()
{
foo a;
a.bar();
return 0;
}
Is my understanding of why the errors occur (see bar2() comment above) correct/incorrect? Either way, I would appreciate an answer with a simplistic overview of how a single-pass C++ compiler would compile the code given above.
For the most part, a C++ file is parsed top-to-bottom, so entities must be declared before they are used.
In your class, bar2 and b are invalid because they both make use of my_int_type, which has not yet been declared.
One exception to the "top-to-bottom" parsing rule is member functions that are defined inside the definition of their class. When such a member function definition is parsed, it is parsed as if it appeared after the definition of the class. This is why your usage of my_int_type in bar is valid.
Effectively, this:
struct foo
{
void bar()
{
my_int_type b;
}
typedef int my_int_type;
};
is the same as:
struct foo
{
void bar();
typedef int my_int_type;
};
inline void foo::bar()
{
my_int_type b;
}
Compiler just starts to go down in a block. Any symbol which is not familiar to it will be considered as a new symbol which is not defined. This is the scheme behind the function definition or header files.
You can suppose that the compiler first makes a list of definitions so the bar() method should get compiled correctly because the definitions have provided before.
It has a lot to do with visibility. I think your confusion may come from assuming a single pass. Think of class parsing as done in two stages.
Parse class definition.
Parse method implementation.
The advantage to this is we have visibility of the entire class from within class member functions.
Apparently C++ lets you define both a struct/class and a function with the same name like this:
struct Foo {
int foo;
Foo(int foo) : foo(foo) {}
};
void Foo(int foo) {}
int main() {
// Works, calls function
Foo(42);
// Doesn't work - compiler error
Foo foo(42);
}
Is this the expected behaviour?
How to create a instance of the Foo struct?
How to avoid that some added library defining a function named like a type in your project causes compiler errors all over the place?
You can write struct or class when you mean the type:
struct Foo foo(42);
class Foo bar(0xdeadbeef);
Yes, this is expected. There is no general way to say "I meant the class, not the function, with this name" because you are not supposed to re-use names.
typename cannot help you here, though since Foo is a class and C++ provides backward compatibility with C's struct T type syntax, you can say class Foo or struct Foo instead:
int main() {
// Calls function
Foo(42);
// Constructs a `[class] Foo`
class Foo foo(42);
}
This is something of a hack, though, and doesn't really solve the fundamental problem which is that the symbols in your program are not clearly differentiated from one another.
Depending on your real circumstances, a namespace might solve your problem in a robust and clear way. Libraries should be using them (but often don't).
Otherwise simply improve your names... and I don't mean by calling one Foo and the other FooClass!
I have been programming in C++ for quite some time and I never thought about this until today.
Consider the following code:
struct foo
{
// compiles fine
void bar()
{
a = 1;
my_int_type b;
b = 5;
}
// Just a declaration, this fails to compile, which leads me to assume that
// even though the bar() method is declared and defined all at once, the
// compiler looks/checks-syntax-of the class interface first, and then compiles
// the respective definitions...?
void bar2(my_int_type); // COMPILE ERROR
my_int_type b; // COMPILE ERROR because it comes before the typedef declaration
typedef int my_int_type;
my_int_type a;
void bar3(my_int_type); // compiles fine
};
int main()
{
foo a;
a.bar();
return 0;
}
Is my understanding of why the errors occur (see bar2() comment above) correct/incorrect? Either way, I would appreciate an answer with a simplistic overview of how a single-pass C++ compiler would compile the code given above.
For the most part, a C++ file is parsed top-to-bottom, so entities must be declared before they are used.
In your class, bar2 and b are invalid because they both make use of my_int_type, which has not yet been declared.
One exception to the "top-to-bottom" parsing rule is member functions that are defined inside the definition of their class. When such a member function definition is parsed, it is parsed as if it appeared after the definition of the class. This is why your usage of my_int_type in bar is valid.
Effectively, this:
struct foo
{
void bar()
{
my_int_type b;
}
typedef int my_int_type;
};
is the same as:
struct foo
{
void bar();
typedef int my_int_type;
};
inline void foo::bar()
{
my_int_type b;
}
Compiler just starts to go down in a block. Any symbol which is not familiar to it will be considered as a new symbol which is not defined. This is the scheme behind the function definition or header files.
You can suppose that the compiler first makes a list of definitions so the bar() method should get compiled correctly because the definitions have provided before.
It has a lot to do with visibility. I think your confusion may come from assuming a single pass. Think of class parsing as done in two stages.
Parse class definition.
Parse method implementation.
The advantage to this is we have visibility of the entire class from within class member functions.
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 refer 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.
Is following code legal C++ or not?
class Foo
{
class Bar;
void HaveADrink(Bar &bar);
void PayForDrinks(Bar &bar);
public:
void VisitABar(int drinks);
};
class Foo::Bar
{
public:
int countDrinks;
};
void Foo::HaveADrink(Bar &bar)
{
bar.countDrinks++;
}
void Foo::PayForDrinks(Bar &bar)
{
bar.countDrinks = 0;
}
void Foo::VisitABar(int drinks)
{
Bar bar;
for (int i=0; i<drinks; i++) HaveADrink(bar);
PayForDrinks(bar);
}
Both Visual C++ and GCC accepts it, however the code seems somewhat strange to me and I would hate to have it refused by some future compiler.
Still, the pattern seems useful to me to reduce compile time dependencies - I often use it to declare structs which are used to pass some "context" (a bunch of variables) which are shared between a few functions which all reside in the same cpp file, and this way I do not have to introduce the "context" definition into the public interface.
legal, and indeed usefull to hide implementation details to the outside world.
[edit]
I originally said this was the "pimpl idiom" : http://c2.com/cgi/wiki?PimplIdiom
but I agree that this is just part of pimpl is about. This technique is used by pimpl.
You're "forwarding" class Bar inside of class Foo. Perfectly legal as long as you don't do anything inside the definigino of Foo that would require the sizeof Bar. You can reference Bar using pointer or reference (Bar* or Bar&), but if you declare a data member in Foo such as this:
private:
Bar _bar;
It wouldn't work. The reason is because the definition of Foo must be enough to determine the sizeof Foo. Since the size of Bar is unknown inside the definition of Foo, it would make the size of Foo indeterminate. But using a pointer would work:
private:
Bar* _bar;
Because the sizeof of pointer is the same, and thus known, regardless of how Bar will be later defined.