Forward defining class in namespace? - c++

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.

Related

Defining sub-structure of sub-class inside parent class

Consider the following snippet of code:
class MyClass
{
private:
struct PrivateClass
{
struct SubStruct;
};
public:
struct PrivateClass::SubStruct {};
private:
PrivateClass::SubStruct member;
};
MSVC and gcc compile this code without any errors. clang, however, produces the following error:
<source>:10:26: error: non-friend class member 'SubStruct' cannot have a qualified name
struct PrivateClass::SubStruct {};
So, who's right? Is this a clang bug?
According to [class]/11 in the C++ 17 Standard:
If a class-head-name contains a nested-name-specifier, the
class-specifier shall refer to a class that was previously declared
directly in the class or namespace to which the nested-name-specifier
refers, or in an element of the inline namespace set (10.3.1) of that
namespace (i.e., not merely inherited or introduced by a
using-declaration), and the class-specifier shall appear in a
namespace enclosing the previous declaration. In such cases, the
nested-name-specifier of the class-head-name of the definition shall
not begin with a decltype-specifier.
So it seems the clang compiler is right.
Standard (latest draft) says:
[class.nest]
If class X is defined in a namespace scope, a nested class Y may be declared in class X and later defined in the definition of class X or be later defined in a namespace scope enclosing the definition of class X.
In this example, the class SubStruct that is declared in the class PrivateClass is defined in neither later in PrivateClass nor later in a namespace scope (but rather, later in a class scope of the outer MyClass). Nor is PrivateClass itself defined in a namespace scope.
Unless there is another rule allowing this, the definition of the sub-nested class as in the example is not at least explicitly allowed. Clang seems to be correct.

std::is_same for a not yet defined/declared class

Is thw following code, a gcc bug?
Checking if T type is a not defined yet class Circle, returns false.
#include <iostream>
using namespace std;
// uncomment to work
//struct Circle;
struct T_traits
{
template<typename T>
constexpr static id() { return is_same<T, class Circle>(); }
};
struct Circle{};
int main()
{
cout << T_traits::id<Circle>() << "\r\n";
return 0;
}
return is_same<T, class Circle>();
This will actually declare a local class called Circle when you comment out the global declaration. [basic.lookup.elab]/2:
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-seqopt 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
[..] the elaborated-type-specifier is a declaration that
introduces the class-name as described in 3.3.2.
The lookup is simple unqualified name lookup as defined in §3.4.1. Lookup is done in the definition context of T_traits as we are not dealing with dependent stuff, so the declaration of Circle right before main is never considered.
§3.3.2/7 (alias [basic.scope.pdecl]/7):
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 namespace or block scope that contains the
declaration. [ Note: These rules also apply within templates. — end
note ]
However, removing the class keyword won't work either - as mentioned before, the identifier isn't dependent and thus looked up in the definition context. If no declaration is found by this lookup, a diagnostic must be issued by the compiler - even if no specialization is instantiated.

Is my interpretation of the word 'first' in §3.3.2/6 correct?

In the snippet below I can understand (from §3.3.2/6 second bullet point) that the name B in the declaration struct B* p; is injected into the global namespace as a class-name.
struct A {
// struct B{};
int B;
struct B* p;
};
void f(B&) {}
int main()
{
A a;
f(*a.p);
}
§3.3.2/6:
The point of declaration of a class first declared in an
elaborated-type-specifier is as follows:
for a declaration of the form
class-key attribute-specifier-seq opt identifier;
the identifier is declared to be a class-name in the scope that
contains the declaration, otherwise
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 namespace or block scope that contains the
declaration. [ Note: These rules also apply within templates. — end
note ] [ Note: Other forms of elaborated-type-specifier do not
declare a new name, and therefore must refer to an existing type-name.
See 3.4.4 and 7.1.6.3. — end note ]
However if I uncomment the definition of struct B{}; inside struct A, what I said earlier with regard to the injection of name B into the global namespace, doesn't occur anymore, as the code doesn't compile. I believe this has to do with the word first (emphasis mine) above, since now the class-name B, in the declaration struct B* p; is no more its first declaration in its declarative region. Am I correct saying this?
Assuming my interpretation is correct, why is it that the class-name B is not injected in the global namespace in this case? Note that the nested class struct B{}; will be hidden inside A in this case, i.e., even if we change the declaration of function f to void f(A::B&) the code won't compile.
There is still one other point that isn't clear to me: what made the implementers to decide for the class-name injection into the namespace, or block scope, containing the elaborated-type-specifier, in the second bullet point above? That is, why didn't they leave the class-name declaration inside the class scope?
You're correct, that first keyword in §3.3.2/6 is also the reason for the following:
struct A {
struct B *p;
struct B{};
int b;
};
void f(B* arg) {
std::cout << std::is_same<decltype(arg), A::B*>::value; // not the same type
}
int main()
{
A a;
f(a.p);
}
why is it that the class-name B is not injected in the global namespace in this case?
As dyp pointed out, [basic.lookup.elab]/2 explains that 3.3.2 is only carried out in case no previous declaration could be found
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-seqopt identifier ;
elaborated-type-specifier is a declaration that introduces the
class-name as described in 3.3.2.the
Finally I tracked down this behavior to possibly be an inheritance from C99 6.7.2.3/p8
If a type specifier of the form
struct-or-union identifier
occurs
other than as part of one of the above forms, and no other declaration
of the identifier as a tag is visible, then it declares an incomplete
structure or union type, and declares the identifier as the tag of
that type.113)
113) A similar construction with enum does not exist.
I would say your interpretation is correct. When you uncomment struct B{};, the struct B* p; line will simply refer to that struct A::B.
To answer your question why, when you leave struct B {}; commented out, the name struct B is inserted into the global scope. I would say that's because the authors didn't want you to (somewhat) silently declare B as a member of A without using a member-specification for the name B.

Why class { int i; }; is not fully standard-conformant?

This is a follow-up question.
In the previous question, #JohannesSchaub-litb said that the following code is not fully standard-conformant:
class { int i; }; //unnamed-class definition. § 9/1 allows this!
and then he added,
while it is grammatically valid, it breaks the rule that such a class must declare at least one name into its enclosing scope.
I couldn't really understand this. What name is he talking about?
Could anyone elaborate on this further (preferably quoting the Standard)?
Clause 9 of the standard allows class {public: int i;} (note the lack of a final semicolon) because this decl-specifier-seq for an unnamed class might be used in some other construct such as a typedef or a variable declaration. The problem with class {public: int i;}; (note that the final semicolon is now present) is that this class specification now becomes a declaration. This is an illegal declaration per clause 7, paragraph 3 of the standard:
In such cases, and except for the declaration of an unnamed bit-field (9.6), the decl-specifier-seq shall introduce one or more names into the program, or shall redeclare a name introduced by a previous declaration.
The point is that by declaring class{ int i; }; you are assembling a bunch of symbol (int i, in this case) you will not be able to use anywhere else in whatever code.
For this code to make sense you should at least do one of the following:
class Myclass { int i; }; //I can furthermore instantiate variables of Myclass
class { int i; } myvar; //This in fact creates a myvar object
typedef class { int i; } MyType; //I can funthermore instantiate variables of MyType
By saying just class{ int i; }; you are saying to the compiler:
keep an int and name it i,
wrap it into a class I'll never call and...
forget it! (};)
If you remove that declaration from your program, nothing will change.
class { int i; }; is not a valid declaration because it is a simple-declaration without an init-declarator-list but it doesn't introduce (or re-declare) a class name.
ISO/IEC 14882:2011 7 [dcl.dcl] / 3:
In a simple-declaration, the optional init-declarator-list can be omitted only when declaring a class (Clause 9) or enumeration (7.2), that is, when the decl-specifier-seq contains either a class-specifier, an elaboratedtype-specifier with a class-key (9.1), or an enum-specifier. In these cases and whenever a class-specifier or enum-specifier is present in the decl-specifier-seq, the identifiers in these specifiers are among the names being declared by the declaration (as class-names, enum-names, or enumerators, depending on the syntax). In such cases, and except for the declaration of an unnamed bit-field (9.6), the decl-specifier-seq shall introduce one or more names into the program, or shall redeclare a name introduced by a previous declaration.
The error message from GCC explains it quite succinctly:
$ cat > a.cc
class { int i; };
$ g++ -Wall -std=c++98 a.cc
a.cc:1: error: abstract declarator ‘<anonymous class>’ used as declaration
class { int i; } is an abstract-declarator (Standard, §8) but not a valid declaration (§7). That's the rule that #JohannesSchaub-litb referenced: for a valid declaration, you need something to be declared, e.g. a class name or variable name.
You are breaking the the [basic.scope.pdecl]/6, which says :
The point of declaration of a class first declared in an elaborated-type-specifier is as follows:
— for a declaration of the form
class-key attribute-specifier-seqopt identifier ;
the identifier is declared to be a class-name in the scope that contains the declaration, otherwise
— 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 namespace or block scope that contains the declaration. [ Note: These rules also apply within
templates. — end note ] [ Note: Other forms of elaborated-type-specifier do not declare a new name,
and therefore must refer to an existing type-name. See 3.4.4 and 7.1.6.3. — end note ]
you are not creating a variable of an anonymous type
you are not create a type
There is another example (in [basic.def]/2) from the standard that proves your example is not standard compliant :
struct S { int a; int b; }; // defines S, S::a, and S::b
struct X { // defines X
int x; // defines non-static data member x
static int y; // declares static data member y
X(): x(0) { } // defines a constructor of X
};
int X::y = 1; // defines X::y
enum { up, down }; // defines up and down
namespace N { int d; } // defines N and N::d
namespace N1 = N; // defines N1
X anX; // defines anX
Your example doesn't define anything (except an anonymous struct, who's fields can not be accessed).
Note an exception about the enum, because this case introduces two values to use.

Is the following equivalent to a forward declaration?

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