void foo()
{
bar(); // error: ‘bar’ has not been declared
}
void bar()
{
}
namespace N
{
void foo()
{
N::bar(); // error: ‘bar’ is not a member of ‘N’
}
void bar()
{
}
}
class C
{
static void foo()
{
C::bar(); // works just fine
}
static void bar()
{
}
};
What is the rationale behind this inconsistency of treating calls to functions above their declaration? How come I can do it inside a class, but not inside a namespace or at global scope?
You can define member functions either inside the class, or after the class declaration, or some of each.
To get some consistency here, the rules for a class with functions defined inline is that it still has to be compiled as if the functions were defined after the class.
Your code
class C {
static void foo()
{
C::bar(); // works just fine
}
static void bar()
{ }
};
compiles the same as
class C {
static void foo();
static void bar();
};
void C::foo()
{ C::bar(); }
void C::bar()
{ }
and now there is no magic in the visibility, because the functions can all see everything declared in the class.
Namespaces can be reopened and new things can be added in any place.
Classes cannot be reopened - all their contents must be put in
single place.
Function prototypes are legal in namespaces but not in classes.
You can write
namespace n
{
void foo();
void bar()
{
foo();
}
void foo()
{
}
}
But not
class C
{
void foo();
void bar()
{
foo();
}
void foo()
{
}
}
So classes need such feature much more and it is much easier to implement it for them than for namespaces.
Well maybe because you have your class declaration in one place, and the compiler can easily obtain the information of it's members.
A namespace, on the other hand, can have it's stuff in tons of different files, and you can't expect the compiler to look through them, because it doesn't know where to look in the first place.
To avoid this, just use function prototypes.
I'm not sure but my thought is that a class
is somewhat an object (badly used) where all its internal components work together (generally speaking), its member will definitely need its methods.
But a namespace is different, functions are not related. It means that a function isnt intended to work with every other functions inside the namespace.
So splitting declaration and definitions is the best thing you could do.
If foo()
needs bar()
its most likely going to be in the same declaration file, and would work that way
See the quote below from the Standard
3.3.7 Class scope [basic.scope.class]
1) The following rules describe the scope of names declared in classes. 1) The potential
scope of a name declared in a class consists not only of the
declarative region following the name’s point of declaration, but also
of all function bodies, default arguments, and
brace-or-equalinitializers of non-static data members in that class
(including such things in nested classes).
2) A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in
the completed scope of S. No diagnostic is required for a violation of this rule.
typedef int c;
enum { i = 1 };
class X {
char v[i]; // error: i refers to ::i
// but when reevaluated is X::i
int f() { return sizeof(c); } // OK: X::c
char c;
enum { i = 2 };
};