The snippet below compiles (demo):
struct A{ int i = 10; };
int main() {
struct A{ int i = 20; };
struct A;
struct A a;
}
But this doesn't:
struct A{ int i = 10; };
int main() {
// struct A{ int i = 20; };
struct A;
struct A a;
}
I can see that the answer is probably given by these paragraphs in the Standard:
[basic.lookup.elab]/2 and [basic.scope.pdecl]/7.
But I really don't know how to deduce the different behaviors shown above from these two paragraphs.
Note that in the first example the struct A is not first declared in the elaborated-type-specifier struct A;, but in the definition of struct A in main().
In the second example, the struct A is also not first declared in the elaborated-type-specifier struct A;, but in the definition of struct Ain global scope.
Each of the examples contains declarations of two different classes, both with the name A.
Let's distinguish between the classes by renaming one of them to B:
struct A{ int i = 10; };
int main() {
struct B{ int i = 20; };
struct B;
struct B b;
}
The above is semantically identical to your first example. The class A is never used.
struct A{ int i = 10; };
int main() {
struct B;
struct B b;
}
This is semantically identical to your second example. You are trying to create an object of an incomplete type, the forward-declared class B.
Renaming B back to A doesn't change anything because then the declaration of A in main shadows the declaration of the other A at global scope.
[basic.lookup.elab]/2
If the elaborated-type-specifier has no nested-name-specifier, and [...] if the elaborated-type-specifier appears in a declaration with the form:
class-key attribute-specifier-seqopt identifier ;
the elaborated-type-specifier is a declaration that introduces the class-name as described in [basic.scope.pdecl].
So struct A; is a declaration that introduces the class name in the scope of the declaration. Under no circumstances can it refer to a class declared in an outer scope.
[basic.scope.pdecl]/7
[ Note: Other forms of elaborated-type-specifier do not declare a new name [...] — end note ]
By implication, this form of elaborated-type-specifier declares a new name.
In the second example the line struct A; is a forward declaration for a struct called A in the main function's scope. This struct will be preferred to the global struct A. The next line defines a variable called a of type struct A. Since a struct A was declared in the main function's scope, that's where the compiler will search for it's definition there. It fails to find one (it's commented out). The first example compiles because there is definition in the same scope. The following example will compile however because it specified that A is in the global namespace :
struct A{ int i = 10; };
int main() {
// struct A{ int i = 20; };
struct A;
struct ::A a;
}
It doesn't compile because it can't find a definition for A.
int main() {
// struct A{ int i = 20; };
struct A;
struct A a;
}
The code above is equal to your first example, as the global A is shadowed by the local A. In the second example A doesn't have a definition. It's just a prototype. Prototypes are supposed to be placed before a piece of code that needs a definition when the definition is placed AFTER the code which needs it.
If the compliler cannot find that definition it will fail because it doesn't know what A is supposed to be (the global definition is shadowed by the local prototype, which causes it to be ignored).
Related
I have the following code:
namespace A {
struct Foo {
int a;
};
}
struct Foo {
int b;
};
struct Bar : public A::Foo {
Bar(Foo foo) {
c = foo.b;
}
int c;
};
C++ compilers complains at "c = foo.b" because A::Foo does not have a member named b.
If I change the type of Bar parameter with ::Foo it works.
My question is what is the rational behind this behaviour (I suppose it has to do with the fact that the inheritance makes Bar enter the A namespace but I cannot find any documentation to support this theory.
Every class has its name injected into it as a member. So you can name A::Foo::Foo. This is called the injected class name.
[class]
2 A class-name is inserted into the scope in which it is declared
immediately after the class-name is seen. The class-name is also
inserted into the scope of the class itself; this is known as the
injected-class-name. For purposes of access checking, the
injected-class-name is treated as if it were a public member name.
[basic.lookup]
3 The injected-class-name of a class is also considered to be a
member of that class for the purposes of name hiding and lookup.
Because unqualified name lookup of the argument type begins in the scope of the class Bar, it will continue into the scope of its base class to account for any member there. And it will find A::Foo::Foo as a type name.
If you want to use the global type name, simply qualify it by its surrounding (global) namespace.
Bar(::Foo foo) {
c = foo.b;
}
Which is doing fully qualified lookup in a scope where the injected class name doesn't appear.
For a followup "why" question see
Why is there an injected class name?
Not a complete answer, only code that shows (since it compiles) that Bar does not enter the namespace A. You can see that when inheriting from A::Foo1 there is no problem with ambiguity of Foo which would be different if this inheritance lets Bar enter A.
namespace A {
struct Foo {
int a;
};
struct Foo1 {
int a;
};
}
struct Foo {
int b;
};
struct Bar : public A::Foo1 {
Bar(Foo foo) {
c = foo.b;
}
int c;
};
I just read this answer, and it completely puzzles me.
I was always thinking a class declaration can appear many times, and only the definition has to exist only once, like:
/*class Class {*/
class A; // (1) forward declaration
class A { // (2) definition, only once
int m;
};
class A; // (3) declaration again, legal?
class A a; // (4) declaration again, legal?
/*};*/
From the linked answer: (3) (and (4)?) is illegal if the code above is nested inside a class (definition and declarations of class A are nested inside class Class).
On cppreference, I found an example of the above, not nested:
struct s { int a; };
struct s; // does nothing (s already defined in this scope)
void g() {
struct s; // forward declaration of a new, local struct "s"
// this hides global struct s until the end of this block
s* p; // pointer to local struct s
struct s { char* p; }; // definitions of the local struct s
}
See the second line.
Question: Given that it is illegal inside a class, is my example code, and the cppreference example above, legal when not nested inside a class? Or more generally: When can a class declaration follow a definition (how is it inside namespaces for example)? If it is legal, why is there a difference?
From [basic.def]:
A declaration (Clause 7) may introduce one or more names into a translation unit or redeclare names introduced by previous declarations.
From [class.name]:
A declaration consisting solely of class-key identifier; is either a redeclaration of the name in the current scope or a forward declaration of the identifier as a class name. It introduces the class name
into the current scope.
So it's generally legal to do this. There's just the one exception in [class.mem]:
A member shall not be declared twice in the member-specification,
except that a nested class or member class template can be declared and then later defined, and except that an enumeration can be introduced with an opaque-enum-declaration and later redeclared with an enum-specifier.
Perfectly OK in namespace scope, not allowed in class scope.
As to why? Well, this rule let's you "forward" declare all the classes you need everywhere you would typically be allowed to do so:
// a.h
struct C;
struct A {
C* c;
};
// b.h
struct C;
struct B {
C& c;
};
without having to worry about somebody actually including the full declaration and breaking everything for you:
// d.h
#include "c.h"
#include "a.h" // now C was already declared!
#include "b.h" // and here too!
struct D { ... };
This isn't so much of a concern within a class definition. It can't exactly span multiple files. So the inability to redeclare nested types doesn't actually achieve anything.
class A; This is a forward declaration of incomplete class A (legal).
class A { int m; }; This is the definition of Class A (legal).
class A; This is re-declaration of class A (legal).
class A a; This is declaration of object a of type A (legal).
The following code compiles in C++
struct foo
{
int a, b;
};
struct foo foo()
{
struct foo a;
return a;
}
int main(void) {
foo();
return 0;
}
Is it supposed to be allowed to have a struct and a function with the same name ?
Since it compiles I then go on and try to declare an object of type foo. Is there a way? It seems impossible to do :
foo a; // error: expected ‘;’ before ‘a’
foo a{}; // error: expected ‘;’ before ‘a’
foo a(); // most vexing parse would kick in any way
Yes, this is allowed we can see this by going to draft C++ standard section 3.3.10 Name hiding paragraph 2 and it says (emphasis mine):
A class name (9.1) or enumeration name (7.2) can be hidden by the name of a variable, data member, function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data member, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is visible.
In this case using struct in the declaration would fix your issue:
struct foo a;
Usually a bad habbit to do something like that. I would name it foo_s or whatever to distinguish it from the function. Other than that, there isn't really a way of doing it.
In C this is possible, since it requires
struct foo
instead of just
foo
as the type name (unless it is typedef'd)
Yes, you can, but it's a really bad pattern to get into.
struct foo
{
};
foo foo(foo& f)
{
return f;
}
int main()
{
struct foo f;
foo(f);
return 0;
}
See livedemo: http://ideone.com/kRK19f
The trick was to specify struct foo when we wanted to get at the type. Note that, until you create this ambiguity, it's actually not necessary to keep saying struct, this isn't C (as in the line foo foo(foo& f)).
Most developers choose a camel casing pattern, e.g they use an upper case letter to distinguish type names and a lowercase letter for a function name:
struct Foo
{
};
Foo foo(); // no ambiguity.
Back in Microsoft's prime, many Windows developers acquired the habit of prefixing struct/class definitions, the definition of a class of thing if you will, with a capital C
struct CFoo
{
};
Now, even if you want to use upper-case first letters for your function names, there is no ambiguity.
Just do it like you would in C, using:
struct foo a;
You might even initialise it like this:
struct foo a{};
struct foo a = {0};
A workaround would be using a typedef, thus avoiding any ambiguity and other difficulties:
typedef struct foo s_foo;
From The.C++.Programming.Language.Special.Edition $A.8:
To preserve C compatibility, a class and a non-class of the same name can be declared in the same
scope ($5.7). For example:
struct stat { /* ... */ };
int stat(char * name, struct stat * buf);
In this case, the plain name (stat) is the name of the non-class. The class must be referred to using
a class-key prefix .
Please educate me. Why does this compile:
struct compiles
{
struct A;
struct B
{
B(const A &a) : member(a.member) { }
int member;
};
struct A
{
A(const B &b) : member(b.member) { }
int member;
};
};
while this does not:
namespace doesnt
{
struct A;
struct B
{
B(const A &a) : member(a.member) { }
int member;
};
struct A
{
A(const B &b) : member(b.member) { }
int member;
};
}
(in MSVC 9.0)
The body of a class/struct/union definition is processed all at once, allowing references to members of classes defined later. A namespace is processed from top to bottom, and a forward declaration of struct A does not allow you to use its members without a definition. Try moving the definition of B's constructor out-of-class so you can put it after the definition of A.
In C++, class scope is special. Any declaration that extends to or past then end of the class definition is automatically extended to the regions defined by its member definitions (3.3.6 [basic.scope.class]).
This means that in the first case both the first declaration of struct A and the full definition of struct A are visible in the body of B and its constructor.
This doesn't apply to namespace scope so in the second case a.member in the constructor of B is an error because a definition of struct A isn't yet visible.
[Also tested with g++ 4.2] The first one compiles because the compiler fully picks up all the types defined within the struct before actually compiling the nested structures (think about public inline methods using private attributes that appear later within the class). Within the namespace the compiler simply works top-to-bottom and doesn't have special rules.
both will compile if you move the implementations of the constructors to the .cpp file where they should be anyway.
I have the following situation:
class Test
{
private:
class SubType
{
//...
};
static std::vector<SubType> v;
};
Because v is static, I initialize it in the cpp file with
std::vector<Test::SubType> Test::v;
But this does not work, the compiler tells me that "Test::SubType" is private.
What can I do about this?
Thanks!
This works for me:
#include <vector>
using namespace std;
class A {
class B {
};
static B b;
static vector <B> vb;
};
A::B A::b;
vector <A::B> A::vb;
I guess you forgot to #include <vector>. Because the following compiles on comeau
#include <vector>
class Test {
class SubType
{
//...
};
static std::vector<SubType> v;
};
std::vector<Test::SubType> Test::v;
Others reported the code compiles fine. I want to supply the Standard wording for backing it up. At 11/5
All access controls in clause 11 affect the ability to access a class member name from a particular scope. The access control for names used in the definition of a class member that appears outside of the member’s class definition is done as if the entire member definition appeared in the scope of the member’s class. [...]
[Example:
class A {
typedef int I; // private member
I f();
friend I g(I);
static I x;
};
A::I A::f() { return 0; }
A::I g(A::I p = A::x);
A::I g(A::I p) { return 0; }
A::I A::x = 0;
Here, all the uses of A::I are well-formed because A::f and A::x are members of class A and g is a friend of class A. This implies, for example, that access checking on the first use of A::I must be deferred until it is determined that this use of A::I is as the return type of a member of class A. ]