namespace M{
void f();
void M::f(){}
}
int main(){}
The above code gives error like so:
"ComeauTest.c", line 3: error:
qualified name is not allowed in
namespace member
declaration
void M::f(){}
And
G++ also gives error.
But
VS2010 compiles fine.
My questions are:
a) What is the expected behavior?
b) $7.3.1.2 does not seem to talk about this restriction. Which portion of the Standard guides the behavior of such code?
Which portion of the Standard guides the behavior of such code?
C++03 Section $8.3 says
A declarator-id shall not be qualified except for the definition of a member function (9.3) or static data member (9.4) out-side of its class, the definition or explicit instantiation of a function or variable member of a namespace out-side of its namespace, or the definition of a previously declared explicit specialization outside of its name-space, or the declaration of a friend function that is a member of another class or namespace (11.4).
So your code is ill-formed.
However in discussing issue 548 the CWG agreed that the prohibition of qualified declarators inside their namespace should be lifted1.
1 : Active Issue 482
7.3.1.2-2 talks specifically about this:
Members of a named namespace can also be defined outside that namespace by explicit qualification (3.4.3.2) of the name being defined, provided that the entity being defined was already declared in the namespace and the definition appears after the point of declaration in a namespace that encloses the declaration’s namespace.
M::f is considered a outside of namespace definition.
Related
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.
I have the following class definition in .h file:
namespace N {
struct S {
S(); // no definition for member here
};
}
And I would like to write definition for class constructor (member in general) in .cpp file. I consider the following two cases:
namespace N {
S::S() { /* definition */ }
}
using namespace N;
S::S() { /* definition */ }
I'm slightly confused why the second is working at all, because never saw this way definition until today. Why the second is working? Some citing from the Standard would be appreciated.
What are the nuances of using one approach instead of the other? Should I prefer the first or the second form?
The reason (2) works is because of these two:
[class.mfct]/4
If the definition of a member function is lexically outside its class
definition, the member function name shall be qualified by its class
name using the :: operator.
[namespace.udir]/2 (emphasis mine)
A using-directive specifies that the names in the nominated namespace
can be used in the scope in which the using-directive appears after
the using-directive. During unqualified name lookup, the names appear
as if they were declared in the nearest enclosing namespace which
contains both the using-directive and the nominated namespace. [ Note:
In this context, “contains” means “contains directly or indirectly”.
— end note ]
The directive simply lets you name S for the :: operator as if you were inside the N namespace (as you are in (1)). But I wouldn't do that. Scoping is good. Definitions should be scoped too.
In this particular example you have declared only one structure in the namespace and defined the function in a separate .cpp file, so it doesn't matter if you use 1 or 2.
Had you declared any other identifiers in the namespace, then 1 should be preferred over 2 as the using declaration kind of defeats the purpose of having a namespace.
The following code produces a compile error (on a recent version of gcc at least):
namespace a {
class X { friend void ::foo(); };
}
The error is:
'void foo()' should have been declared inside '::'
If we remove :: from the declaration, according to the standard, foo will be introduced into the namespace a (although it won't be visible). Predeclaring foo inside of a is not required.
My question is, given the above, why is predeclaring within the global namespace a requirement? Why doesn't the name foo become a member of the global namespace? I couldn't find any paragraph in the standard that would explicitly forbid that either, so I'm curious to know.
The paragraph you're looking for is [dcl.meaning] (8.3 (1) in C++11):
(...) A declarator-id shall not be qualified except for the definition of a member function or static data member outside of its class, the definition or explicit instantiation of a function or variable of a namespace outside of its namespace, or the definition of an explicit specialization outside of its namespace, or the declaration of a friend function that is a member of another class or namespace. When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers (or, in the case of a namespace, of an element of the inline namespace set of that namespace).
(emphasis mine) What this means is that you cannot write
namespace a { }
void a::foo() { }
unless a::foo is already declared with an unqualified declarator inside the namespace. And since there is no exception for friends, you cannot do this for friends either.
A footnote in [namespace.memdef] (7.3.1.2 (3) in C++11) mentions this even more explicitly for the special case of friends:
(...) If a friend declaration in a non-local class first declares a class or function95 the friend class or function is a member of the innermost enclosing namespace. (...)
95) This implies that the name of the class or function is unqualified.
While refactoring some C++ code today I got some code which boils down to the following
class x
{
public:
void x::y();
};
Does the x:: scope resolution operator do anything here, is it a bug, or is it something else. My best guess is that it is an artefact left over by some autocomplete but I'm curious to know if I'm missing anything. Compiler in use is VS2010 SP1.
It's a bug, and most compilers will reject it. For example, GCC says
prog.cpp:4:10: error: extra qualification ‘x::’ on member ‘y’ [-fpermissive]
void x::y();
^
The redundant qualifier is disallowed by C++11 8.3/1:
A declarator-id shall not be qualified except for the definition of a member function or static data member outside of its class, the definition or explicit instantiation of a function or variable member of a namespace outside of its namespace, or the definition of an explicit specialization outside of its namespace, or the declaration of a friend function that is a member of another class or namespace.
with none of those exceptions applying to a member declaration inside its class.
I'm working on a C++ project where, among other things, I have an interface with a few pure virtual methods. The problem arises when I try to implement that interface - IntelliSense doesn't seem to agree with the derived class's method declaration. An example of such a method:
// DLL_EXPORT -> #define DLL_EXPORT __declspec(dllexport)
// IPlayer
DLL_EXPORT virtual const Grid& GetGrid() const = 0;
Declaration in one of the derived classes:
// Human : IPlayer
DLL_EXPORT const Grid& IPlayer::GetGrid() const;
The error it keeps nagging me with - "IntelliSense: declaration must correspond to a pure virtual member function in the indicated base class". The code compiles without errors and runs fine, all of the "problematic" methods do their jobs as expected during run time. What is worth mentioning is that the error disappears if I remove the IPlayer:: scope qualifier in the derived class. I wanted to keep it there for readability reasons. Also, I am NOT proficient in C++ so there could be something obviously wrong with the example I've provided.
Minimized example:
struct C { virtual void f() = 0; };
struct D : C { void C::f() { } };
This doesn't compile in any version of g++ or clang that I tested. Intellisense in VS2013 uses the EDG frontend, and to quote Jonathan Wakely, "If GCC, Clang and EDG all agree and MSVC disagrees that usually means MSVC is wrong."
To make things more interesting, the relevant paragraphs in the standard actually changed between C++11 and C++14.
In C++11, this is flat-out illegal (N3337 §8.3 [dcl.meaning]/p1):
A declarator-id shall not be qualified except for the definition of a
member function (9.3) or static data member (9.4) outside of its
class, the definition or explicit instantiation of a function or
variable member of a namespace outside of its namespace, or the
definition of an explicit specialization outside of its namespace, or
the declaration of a friend function that is a member of another class
or namespace (11.3).
This sentence was removed in C++14 as a result of CWG issue 482. The proposed resolution for that issue has the following note:
[Drafting note: The omission of “outside of its class” here does not
give permission for redeclaration of class members; that is still
prohibited by 9.2 [class.mem] paragraph 1. The removal of the
enumeration of the kinds of declarations in which a qualified-id can
appear does allow a typedef declaration to use a qualified-id, which
was not permitted before; if that is undesirable, the prohibition can
be reinstated here.]
In C++14, the only applicable rule in §8.3 [dcl.meaning]/p1 is now (quoting N3936):
When the declarator-id is qualified, the declaration shall refer to a
previously declared member of the class or namespace to which the
qualifier refers (or, in the case of a namespace, of an element of the
inline namespace set of that namespace (7.3.1)) or to a specialization
thereof; the member shall not merely have been introduced by a
using-declaration in the scope of the class or namespace nominated by
the nested-name-specifier of the declarator-id.
The relevant part of §9.2 [class.mem]/p1 is:
Except when used to declare friends (11.3) or to introduce the name of
a member of a base class into a derived class (7.3.3),
member-declarations declare members of the class, and each such
member-declaration shall declare at least one member name of the
class. 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.
Since a using-declaration "to introduce a member of a base class into a derived class" is made an explicit exception, it appears that base class members are not considered members for the purposes of the rule that "member-declarations declare members of the class, and each such member-declaration shall declare at least one member name of the class". If so, then it follows that using a qualified-id like void C::f() { } in a member-declaration is also not allowed in C++14, since that qualified-id refers to a member of C, not a member of D.