命名空间范围的构造函数定义是否需要类限定标识符?
这是我们在 C++ 第一天学到的东西,我们认为这是理所当然的,但并没有明确遵循标准的措辞。
给定一个类S
,我们可以定义它的构造函数
struct S { S(); };
S::S() { … }
,但标准似乎也允许这样做:
struct S { S(); };
S() { … }
用自身来限定类的名称总是允许的,但总是多余的。例如 S::S::S::S() { … }
也是一个有效的声明。如果 S::S
是,为什么不直接使用 S
呢?
从 C++11 §12.1/1 开始,
构造函数没有名称。使用特殊的声明符语法来声明或定义构造函数。语法使用:
——一个可选的 decl-specifier-seq,其中每个 decl-specifier 都是函数说明符或 constexpr,
——构造函数的类名,以及
——参数列表
按照这个顺序。
。这同样适用于类或命名空间范围。关于命名空间范围有一条特殊规则,§9.3/5,
如果成员函数的定义在词法上位于其类定义之外,则应使用 :: 运算符通过其类名来限定成员函数名称。
但是,构造函数没有名称,所以这不适用,对吗?此外,没有理由要求限定,因为不存在语法歧义。根据当前观察到的规则,声明为无返回类型和标识符的类名的函数始终是语法错误。正确的?
并不是说我们应该在省略限定条件的情况下开始编写代码,但是是否有任何编译器不接受这一点的原因,或者这只是传统?
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,
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的,它说,
但它不说没有名称的成员函数不由它的类名限定。是吗? ;)
这似乎会导致一个不确定的领域,具体取决于实现。然而,A::A 的形式是由标准定义的。
5.1 主要表达式
至于是否允许
A(){..}
或不,我想没有理由按照惯例这样做(是否有任何 C++ 编译器允许这样做? AFAIK,不):由于构造函数是一个特殊的成员函数,因此
A::A( 的方式){..}
更多与其他成员功能一致。为什么要让它表现得特别呢?这可能不值得。没有人愿意冒编写标准中未明确规定的不合规代码的风险。
Yes, it says that,
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
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.
当在命名空间范围内遇到标记
S() { }
时,编译器无法神奇地确定它是一个 ctor。哪种语法规则会产生这样的标记序列?让我们忽略除函数定义之外的所有内容;他们无法生成( ){ }
部分。这意味着
S()
必须是一个 声明符 ,并且 decl-specifier-seqopt 必须是空(参见§8.4.1)。 §9.2/7 随后告诉我们声明符必须命名构造函数、析构函数或转换函数。但S
也没有命名。因此,S() { }
无效。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. ButS
doesn't name either. Therefore,S() { }
is invalid.尽管这个问题在最初发布的 C++11 标准中充其量是不明确的,并且在提出这个问题时,缺陷解决方案 1435 于 2013 年 4 月被接受,更改了相关文本,以便在命名空间范围内定义构造函数确实需要一个qualified-id(使用
::
的语法)作为“名称”。C++14 中的同一段落(或接近那个时间)是:
本段还有一些细微的调整,但没有改变这个问题的答案。 当前版本内容如下:
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:
This paragraph has had a few more minor tweaks, none altering the answer to this question. The current version reads: