Does a namespace-scope constructor definition require a class-qualified identifier?
Here's something we all learned on Day 1 of C++, which we take for granted but doesn't clearly follow from the wording of the Standard.
Given a class S
, we can define its constructor
struct S { S(); };
S::S() { … }
But the Standard seems to allow this just as well:
struct S { S(); };
S() { … }
Qualifying the name of a class with itself is always allowed but always redundant. For example S::S::S::S() { … }
is also a valid declaration. If S::S
is, why not plain S
?
From C++11 §12.1/1,
开发者_Python百科Constructors do not have names. A special declarator syntax is used to declare or define the constructor. The syntax uses:
— an optional decl-specifier-seq in which each decl-specifier is either a function-specifier or constexpr,
— the constructor’s class name, and
— a parameter list
in that order.
This applies equally to class or namespace scope. There is a special rule about namespace scope, §9.3/5,
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.
However, constructors do not have names, so this doesn't apply, right? Moreover, there's no reason to require the qualification, because there is no syntactic ambiguity. A function declared with no return type and a class-name for an identifier is always a syntax error under currently observed rules. Right?
Not that we should start writing code with the qualification omitted, but is there a reason that no compiler accepts this, or is it just tradition?
Yes, it says that,
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.
But it doesn't says that member function w/o name shall not be qualified by its class name. Does it? ;)
That seems to lead to an uncertain area depending on implementations. However, the form of A::A is defined by the Standard.
5.1 Primary Expressions
Where class-name :: class-name is used, and the two class-names refer to the same class, this notation names the constructor..
As to whether A(){..}
is allowed or not, I guess there is no reason to do it conventionally(Is there ANY C++ compiler allow it?? AFAIK, nope):
Since constructor is a special member function, the way of
A::A(){..}
is more consistent with other member functions. Why borther allow it to behave specially? That's probably not worth the effort.No one wants to run the risk of writing non-compliant code that's not explicitly stated in the Standard.
When faced with the tokens S() { }
at namespace scope, the compiler can't magically decide it's a ctor. Which grammar rule would produce such a sequence of tokens? Let's ignore everything but function-definitions; they can't produce the ( ){ }
part.
That means that S()
must be a declarator , and the decl-specifier-seqopt has to be empty (see §8.4.1). §9.2/7 subsequently tells us that the declarator must name a constructor, destructor, or conversion function. But S
doesn't name either. Therefore, S() { }
is invalid.
Although this question was ambiguous at best in the originally published C++11 Standard and at the time of this question, Defect Resolution 1435 was accepted in April 2013, changing the relevant text so that a constructor definition at namespace scope does require a qualified-id (the syntax using ::
) as the "name".
The same paragraph in C++14 (or near that time) was:
Constructors do not have names. A declaration of a constructor uses a function declarator ([dcl.fct]) of the form
ptr-declarator
(
parameter-declaration-clause)
exception-specificationopt attribute-specifier-seqoptwhere the ptr-declarator consists solely of an id-expression, an optional attribute-specifier-seq, and optional surrounding parentheses, and the id-expression has one of the following forms:
- in a member-declaration that belongs to the member-specification of a class but is not a friend declaration ([class.friend]), the id-expression is the injected-class-name ([class]) of the immediately-enclosing class;
- in a member-declaration that belongs to the member-specification of a class template but is not a friend declaration, the id-expression is a class-name that names the current instantiation ([temp.dep.type]) of the immediately-enclosing class template; or
- in a declaration at namespace scope or in a friend declaration, the id-expression is a qualified-id that names a constructor ([class.qual]).
This paragraph has had a few more minor tweaks, none altering the answer to this question. The current version reads:
A declarator declares a constructor if it is a function declarator ([dcl.fct]) of the form
ptr-declarator
(
parameter-declaration-clause)
noexcept-specifieropt attribute-specifier-seqoptwhere the ptr-declarator consists solely of an id-expression, an optional attribute-specifier-seq, and optional surrounding parentheses, and the id-expression has one of the following forms:
- in a friend declaration ([class.friend]), the id-expression is a qualified-id that names a constructor ([class.qual]);
- otherwise, in a member-declaration that belongs to the member-specification of a class or class template, the id-expression is the injected-class-name ([class.pre]) of the immediately-enclosing entity;
- otherwise, the id-expression is a qualified-id whose unqualified-id is the injected-class-name of its lookup context.
Constructors do not have names. ...
精彩评论