这是我们在C ++第1天学到的东西,我们认为这是理所当然的,但并没有明确遵循标准的措辞。
给定一个类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,
如果成员函数的定义在词法定义之外是词法定义,则成员函数名称应使用::运算符通过其类名限定。
但是,构造函数没有名称,所以这不适用,对吧?而且,没有理由要求资格,因为没有语法歧义。在当前观察到的规则下,声明为没有返回类型和标识符的类名的函数始终是语法错误。正确?
不是我们应该开始编写省略资格的代码,但是有没有编译器接受这个的原因,或者它只是传统吗?
答案 0 :(得分:3)
是的,它说,
如果成员函数的定义在词法定义之外是词法上的 成员函数名称应使用:: operator。
通过其类名限定
但 不 表示没有名称的会员功能 不 由其认可班级名称。可以? ;)
根据实施情况,这似乎会导致不确定的区域。但是,A :: A的形式由标准定义。
5.1主要表达
使用class-name :: class-name,并且两个类名引用同一个类,这个表示法命名构造函数。
关于是否允许A(){..}
,我想没有理由按常规进行(是否有任何C ++编译器允许它?AFAIK,nope):
由于构造函数是一个特殊的成员函数,A::A(){..}
的方式与其他成员函数更加一致。为什么borther允许它特别表现?这可能不值得付出努力。
没有人愿意承担编写标准中未明确规定的不合规代码的风险。
答案 1 :(得分:1)
当在命名空间范围内遇到令牌S() { }
时,编译器不能神奇地决定它是一个ctor。哪种语法规则会产生这样一系列令牌?让我们忽略除函数定义之外的一切;他们不能产生( ){ }
部分。
这意味着S()
必须是声明符,而 decl-specifier-seq opt 必须为空(见§8.4.1)。 §9.2/ 7随后告诉我们声明符必须命名构造函数,析构函数或转换函数。但S
也未命名。因此,S() { }
无效。
答案 2 :(得分:1)
尽管这个问题在最初发布的 C++11 标准中充其量是模棱两可的,并且在这个问题出现时,Defect Resolution 1435 于 2013 年 4 月被接受,更改了相关文本,以便命名空间范围内的构造函数定义确实需要 qualified-id(使用 ::
的语法)作为“名称”。
C++14(或接近那个时间)中的同一段是:
<块引用>构造函数没有名字。构造函数的声明使用形式为
的函数声明符 ([dcl.fct]) ptr-declarator (
parameter-declaration-clause )
异常规范opt attribute-specifier-seqopt
其中 ptr-declarator 仅由一个 id-expression、一个可选的 attribute-specifier-seq 和可选的环绕括号组成,并且 id-expression 具有以下形式之一:
这一段有一些更小的调整,没有改变这个问题的答案。 current version 内容如下:
<块引用>declarator 声明一个 构造函数,如果它是一个函数声明符 ([dcl.fct])
ptr-declarator (
parameter-declaration-clause )
noexcept-specifieropt attribute-specifier-seqopt
其中 ptr-declarator 仅由一个 id-expression、一个可选的 attribute-specifier-seq 和可选的环绕括号组成,并且 id-expression 具有以下形式之一:
构造函数没有名字。 ...