I accidentally happened to find this in one of the source codes I was looking at. So, I'm giving a similar smaller example here.
In the file test.h:
#include<iostream>
class test{
int i;
public:
test(){}
//More functions here
};
In the file test.cpp:
#include "test.h"
int main()
{
test test1;
test::test test2;
test::test::test test3;
return 0;
}
First of all, is there a reason to declare test2 that way? Secondly, this code compiles just fine in g++ version 4.4.3 and lower versions. Is there something in the C++ standard, saying, scope resolution operators are ignored when there is no need to resolve scope?
This code is not valid.
It was a bug in g++ that it accepted the code. See "g++ does not treat injected class name correctly." The bug was resolved as fixed in 2009, so it should be fixed in any recent version of g++.
To clarify the situation, as specified in §9/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.
However, as specified in §3.4.3.1/1:
If the nested-name-specifier of a qualified-id nominates a class, the name specified after the nested-namespecifier is looked up in the scope of the class (10.2), except for the cases listed below.
[ ... §3.4.3.1/2]:
In a lookup in which the constructor is an acceptable lookup result and the nested-name-specifier nominates a class C:
— if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C (Clause 9) [ ... ] the name is instead considered to name the constructor of class C.
[ ... example: ]
struct A { A(); };
[ ... ]
A::A a; // error, A::A is not a type name
struct A::A a2; // object of type A
Related
Consider this code:
struct foo{};
int main() {
foo::foo a;
}
I would expect this to be well-formed, declaring a variable of type foo by the rule in [class]/2 (N4140, emphasis mine):
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.
clang 3.6.0 agrees with me, compiling the above code with no applicable warnings with -Wall -pedantic.
gcc 5.2.0 disagrees, providing the following error message:
main.cpp: In function 'int main()':
main.cpp:5:5: error: 'foo::foo' names the constructor, not the type
foo::foo a;
The above holds no matter how deep the nesting of injected class names, e.g. foo::foo::foo::foo.
Is there a rule which forces that construct to be interpreted as a constructor in that context, or is this agcc bug? Or am I interpreting the standards quote incorrectly?
It appears that clang is wrong in this case. The relevant exception I was looking for is in [class.qual]/2:
2 In a lookup in which function names are not ignored and the nested-name-specifier nominates a class C:
(2.1)
if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C, or
[...]
the name is instead considered to name the constructor of class C.
The standard has a near-equivalent (non-normative, obviously) example:
struct A { A(); };
struct B: public A { B(); };
A::A() { }
B::B() { }
B::A ba;// object of type A
A::A a;// error, A::A is not a type name
struct A::A a2;// object of type A
However, clang actually issues a correct diagnostic in this case:
error: qualified reference to 'A' is a constructor name rather than a type wherever a constructor can be declared
Perhaps clang interprets the line In a lookup in which function names are not ignored as In a lookup in which a constructor declaration is valid, but that doesn't seem to be a correct interpretation.
There is an existing bug for this in the clang bugzilla.
Relevant, but not an answer: The GCC people discussed exactly this for years and figured that it should not be accepted. They explicitly made this an error in GCC 4.5 and newer - in 4.4.7 it was accepted.
BTW: You probably want to use Clang's -Weverything instead of -Wall -pedantic when investigating such stuff.
I think this is the subject of language defect #147
which contains this example
class B { };
class A: public B {
A::B ab; // B is the inherited injected B
A::A aa; // Error: A::A is the constructor
};
At least gcc seems to believe that. :-)
Consider the following code snippet:
class A
{
int b[A::a]; //1, error
void foo(){ int b = A::a; } //2, ok
static const int a = 5;
}
Clause 3.4.3.1/1 (Qualified name lookup, class members) said:
If the nested-name-specifier of a qualified-id nominates a class, the
name specified after the nested-name-specifier is looked up in the
scope of the class (10.2)
This implies that the name a after the nested-name-specifier both in //1 and in //2 will be looked up in the class scope.
Clause 10.2 (Member name lookup) said:
10.2/2
The following steps define the result of name lookup for a member name
f in a class scope C.
10.2/3
The lookup set for f in C, called S(f, C)...
S(f, C) is calculated as follows:
10.2/4
If C contains a declaration of the name f, the declaration set
contains every declaration of f declared in C that satisfies the
requirements of the language construct in which the lookup occurs.
The following is unclear for me:
From the quotes I cited implies that for both //1 and //2 the same member lookup rules shall be applied. But actually its a different. Why is my reasoning wrong?
Note: I know about unqualified name lookup rules into the class scope. And I understood that behavior in the following code snippet:
class A
{
int b[a]; //error
void foo(){ int b = a; } //ok
static const int a = 5;
}
It is because that behavior described in the sections 3.4.1/7 and 3.4.1/8 (Unqualified name lookup).
The error is because when int b[A::a]; is being processed, A does not yet have a symbol a. At that point of compilation, A is still incomplete because we have not reached the closing } of the class definition yet. The compiler doesn't "look ahead" to see if future lines of source code contain a definition of a.
You can see this by reversing the order of the lines:
class A
{
static const int a = 5;
int b[A::a]; // OK
};
The function definition does not have the same problem because inline function bodies are not compiled until after compilation of the class definition. (Sorry, I don't have standard references handy for this)
The member declaration int b[A::a]; is not in the potential scope of A::a (3.3.7p1), while the body of void A::foo() is in the potential scope (3.3.7p1b1):
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, brace-or-equal-initializers of non-static data members, and default arguments in that class (including such things in nested classes).
3.4.3.1p1 references the potential scope rule in a note:
[...] [ Note: A class member can be referred to using a qualified-id at any point in its potential scope (3.3.7). — end note ] [...]
Of course, notes are non-normative, so the conclusion must be that the potential scope rule is implied by other material in the standard. I believe this other material is specifically 3.3.2p5:
After the point of declaration of a class member, the member name can be looked up in the scope of its class. [...]
By implication, prior to the point of declaration of that class member, that member name cannot be looked up in the scope of that class.
I hope the title actually describes what I wanted to ask...
I wrote a piece of code that compiles with gcc and works as I intended. However, it does not compile with llvm and the code executes differently when compiled with icc!
Here is an example of the problem:
#include <iostream>
using std::cout; using std::endl;
class A {
public:
virtual void foo() { cout << "A::foo()" << endl; }
};
class B : public A {
public:
typedef A base;
virtual void foo() { cout << "B::foo()" << endl; }
};
int main() {
typedef B base;
base* bp = new B();
bp->base::foo();
}
gcc output: A::foo()
icc output: B::foo()
Could somebody explain what does the standard say about this case?
From C++11, §3.4.5/4:
If the id-expression in a class member access is a qualified-id of the
form
class-name-or-namespace-name::...
the class-name-or-namespace-name
following the . or -> operator is first looked up in the class of the
object expression and the name, if found, is used. Otherwise it is
looked up in the context of the entire postfix-expression.
I don't think it can be clearer. This finds B::base, so the output
should be A::foo().
I think this part of the standard is relevant:
3.4.3.1 Class members [class.qual]
1) If the nested-name-specifier of a qualified-id nominates a class, the name specified after the
nested-namespecifier is looked up in the scope of the class (10.2),
except for the cases listed below. The name shall represent one or
more members of that class or of one of its base classes (Clause 10).
[ Note: A class member can be referred to using a qualified-id at any
point in its potential scope (3.3.7). —end note ] The exceptions to
the name lookup rule above are the following:
— a destructor name is
looked up as specified in 3.4.3;
— a conversion-type-id of a
conversion-function-id is looked up in the same manner as a
conversion-type-id in a class member access (see 3.4.5);
— the names
in a template-argument of a template-id are looked up in the context
in which the entire postfix-expression occurs.
— the lookup for a name
specified in a using-declaration (7.3.3) also finds class or
enumeration names hidden within the same scope (3.3.10).
base:: in this case seems to "nominate" a class, so the look up is done in scope of the class. I don't see how any of the exception cases could apply, so it is the scope of the class, as such base is equivalent to A.
(5.1.1-8 indicates that it is a qualified-id in that case and that 3.4.3.1 applies)
This is related to a recent question.
Basically the following code:
class A
{
class B* b;
B* c;
};
compiles although class B is not declared or forward-declared. Is this syntax equivalent to a forward declaration? Are there any differences?
You can declare a type and an object in the same declaration.
class B* b;
Declares a type, B and an object b which has type pointer to B. The type is incomplete and is looked up in the scope in which it occurs, if the lookup fails to find an existing declaration for the class then the type names a type in the nearest enclosing namespace scope (strictly non-class non-function-prototype scope, which is usually a namespace). The object is a member of the scope in which the declaration appears (in this case, class A).
In most cases it's more common to declare a complete type and an object together, in this case the type is sometimes left anonymous. E.g.
struct { int a; int b; } x;
The relevant parts of the standard for the name scoping rules are 7.1.5.3 [dcl.type.elab] Elaborated type specifiers / 2 and the referenced sections in 3.4.4 and 3.3.1 :
3.4.4 describes how name lookup proceeds for the identifier in an elaborated-type-specifier. If the identifier resolves to a class-name or enum-name, the elaborated-type-specifier introduces it into the declaration the same way a simple-type-specifier introduces its type-name. If the identifier resolves to a typedef-name or a template type-parameter, the elaborated-type-specifier is ill-formed. [ ... ] If name lookup does not find a declaration for the name, the elaborated-type-specifier is ill-formed unless it is of the simple form class-key identifier in which case the identifier is declared as described in 3.3.1.
No, it's a declaration, of a pointer to B. You are not declaring B here, only a pointer to it, and there's nothing forward about it.
Edit: I was wrong, sorry. See other answer.
I would like to add few details to answer of Charles Bailey:
class A
{
public:
class B * b;
class C {} *c;
int d;
} a;
B* globalB;
// C* globalC; identifier "C" is undefined here
int main(int argc, char *argv[])
{
a.d = 1;
cout << a.d;
}
Yes, it defines incomplete type B and b as a pointer to B at once. But here comes the fun:
"An exception to the scope visibility of a nested class declaration is when a type name is declared together with a forward declaration. In this case, the class name declared by the forward declaration is visible outside the enclosing class, with its scope defined to be the smallest enclosing non-class scope." (Nested Class Declarations)
Which means that type B is defined out of scope A which allows you to define variable globalB. If you don't want B to be defined out of scope A, you can use {} just like it is used with type C in my example.
By the way, this example is correct and its output is: 1
The following snippet fails to compile with Visual Studio 2010, but GCC likes it:
namespace Test {
class Baz;
// Adding class Bar; here and removing the class below makes it work
// with VC++, but it should work like this, shouldn't it?
void Foo (Baz& b, class Bar& c);
}
namespace Test {
class Bar
{
// Making this method non-template works
template <typename T>
static void Lalala ()
{
}
};
}
int main ()
{
}
Am I doing something stupid here or is this a valid compiler bug? The error I get is:
error C2888: 'void Bar::Foo(void)' : symbol cannot be defined within namespace 'Test'
It compiles with GCC 4.5.1: http://ideone.com/7sImY
[Edit] Just to be clear, I want to know if this is valid C++ or not (and if so, why not) -- workarounds to get it compiled are nice but not part of this question.
Well, I tried it in codepad.org too and it compiles, but I'm not sure it should (not THAT proficient in C++ compiler functionality)!
Workaround: forward declare Bar as well or you have to define Bar before you make Foo. In other words, this compiles in MSVC:
namespace Test
{
class Baz;
class Bar;// also forward-declare Bar
void Foo (Baz& b, class Bar& c);
}
namespace Test
{
class Bar
{
template <typename T>
static void Foo ()
{
}
};
}
int main(void)
{
return 0;
}
Update:
I think that this might already be a bug reported to Microsoft... this looks pretty close: http://connect.microsoft.com/VisualStudio/feedback/details/99218/invalid-error-c2888-when-a-class-is-defined-after-it-is-declared
The workaround cited by Microsoft:
A stand-alone forward declaration consists of an elaborated type specifier followed by a semicolon.
insert the declaration
class C2888;
before the declaration of foo(C2888o, C2888).
I think the code is well-formed. But proving that for certain would require making sure there's nothing in the Standard that contradicts the usage.
Some relevant quotes from the C++11 Standard:
3.3.2 p6:
The point of declaration of a class first declared in an elaborated-type-specifier is as follows:
for an elaborated-type-specifier of the form class-key identifier
if the elaborated-type-specifier is used in the decl-specifier-seq or parameter-declaration-clause of a
function defined in namespace scope, the identifier is declared as a class-name in the namespace that
contains the declaration; otherwise, except as a friend declaration, the identifier is declared in the
smallest non-class, non-function-prototype scope that contains the declaration.
3.4.4 p2:
If the elaborated-type-specifier has no nested-name-specifier, and unless the elaborated-type-specifier appears in a declaration with the following form:
class-key attribute-specifier-seq opt identifier ;
the identifier is looked up according to 3.4.1 but ignoring any non-type names that have been declared. ... If the elaborated-type-specifier is introduced by
the class-key and this lookup does not find a previously declared type-name, or if the elaborated-type-specifier
appears in a declaration with the form:
class-key attribute-specifier-seq opt identifier ;
the elaborated-type-specifier is a declaration that introduces the class-name as described in 3.3.2.
7.1.6 has some syntax definitions establishing that an elaborated-type-specifier can syntactically be a type-specifier. 7.1 establishes that a type-specifier can syntactically be a decl-specifier, which is the syntactical unit used as the type in a function parameter-declaration (8.3.5).
Probably it is a compiler bug.
Changing the order of parameters will change the compilation result.
namespace Test {
void Foo (class Bar& b, class Baz& c) - will compile.
}
The class Bar construct is erroneous. Are you, by any chance, a C programmer who didn't use typedef struct { /* members */ } Foo?
Anywho, you need to define both Bar and Baz inside test:
namespace Test {
class Bar;
class Baz;
};
And remove class, struct, union, and enum keywords when declaring function parameters.
With that modification, it compiles cleanly in g++4.6.