名称空间作用域构造函数定义是否需要类限定的标识符
Does a namespace-scope constructor definition require a class-qualified identifier?
这是我们在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,
但是,构造函数没有名称,所以这个不适用,对吗?此外,没有理由要求限定,因为没有语法歧义。在当前观察到的规则下,没有返回类型和标识符的类名声明的函数总是语法错误。对吧?如果成员函数的定义在词法上超出其类定义,则成员函数名应使用::操作符由其类名限定。
并不是说我们应该开始写省略限定符的代码,而是没有编译器接受这一点的原因,或者这只是传统?
是的,它说,
如果成员函数的定义在词法上超出其类定义成员函数名应使用::操作符由类名限定。
但是它没有说没有名字的成员函数不能被它的类名限定。不是吗?;)
这似乎导致了一个依赖于实现的不确定区域。但是,A::A的形式是由标准定义的。
5.1主表达式如果使用了class-name:: class-name,并且两个类名指向同一个类,则用这种表示法命名构造函数。
至于是否允许A(){..}
,我想没有理由按照惯例这样做(是否有任何c++编译器允许它??)AFAIK不):
由于constructor是一个特殊的成员函数,所以
A::A(){..}
的方式与其他成员函数更加一致。为什么要让它表现得特别呢?没有人愿意冒险去编写标准中没有明确规定的不兼容代码。
当在命名空间范围内面对令牌S() { }
时,编译器不能神奇地确定它是一个actor。哪个语法规则会产生这样的符号序列?让我们忽略函数定义之外的所有内容;他们不能生产( ){ }
部件。
S()
必须是声明符,并且decl-specifier-seqopt必须为空(参见§8.4.1)。§9.2/7随后告诉我们,声明符必须命名构造函数、析构函数或转换函数。但S
没有点名。因此,S() { }
无效
虽然这个问题在最初发布的c++ 11标准中充其量是模棱两可的,在这个问题出现的时候,缺陷决议1435在2013年4月被接受,改变了相关文本,以便在命名空间范围内的构造函数定义确实需要一个限定id(使用::
的语法)作为"名称"。
在c++ 14(或接近那个时间)中相同的段落是:
构造函数没有名称。构造函数的声明使用形式为
的函数声明符([dcl.fct])ptr-declarator
(
参数声明子句)
exception-specificationoptattribute-specifier-seqopt,其中ptr声明符仅由id-expression、可选的属性指定符-seq和可选的环绕括号组成,并且id-expression具有以下形式之一:
- 在属于类的成员规范但不是友元声明([class.friend])的成员声明中,id-expression是直接封闭类的注入类名([class]);
- 在属于类模板的成员规范但不是友元声明的成员声明中,id-expression是一个类名,它命名了立即封闭的类模板的当前实例化([temp. depth .type]);或
- 在命名空间范围的声明或友元声明中,id-表达式是一个限定id,用于命名构造函数([class. equal])。
这一段有一些更小的调整,没有改变这个问题的答案。当前版本为:
如果声明器是形式为
的函数声明器([dcl.fct]),则声明构造器ptr-declarator
(
参数声明子句)
noexcept-specifieroptattribute-specifier-seqopt,其中ptr声明符仅由id-expression、可选的属性指定符-seq和可选的环绕括号组成,并且id-expression具有以下形式之一:
- 在友元声明([class.friend])中,id-表达式是一个限定id,用于命名构造函数([class. equal]);
- 否则,在属于类或类模板的成员规范的成员声明中,id-表达式是直接封闭实体的注入类名([class.pre]);
- 否则,id-expression是一个限定id,其unqualified-id是其查找上下文的注入类名。
构造函数没有名称. ...
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 是否有一种工具可以识别一组C++源文件所指的外部标识符
- 将以"_[a-z0-9]"开头和"using"的标识符导入全局命名空间是否定义良
- C 17是否允许非ASCII字符作为标识符
- 从<T>派生类访问 Base 标识符是否必须>?
- 在检查传递函数标识符时是否获得模板参数时遇到问题
- 是否有任何法律语法允许引号出现在 javascript 中的标识符字符旁边?(如"so")
- 使用函数模板中静态局部变量的地址作为类型标识符是否安全
- 结构化绑定的标识符是否按顺序初始化?
- 如果当标识符的库未直接包含在源中时,是否可以强制视觉工作室抛出错误?
- 标识符规则是否适用于运算符重载函数
- 错误:标识符<uint8_t>未定义,是否可以在 openCV 上使用
- 我是否可以在不使用资源的情况下为Win32控件分配标识符代码
- C++11是否允许在标识符中使用美元符号
- 在C++中使用标准库函数名称作为标识符是否有效
- 根据编译时常量,使用相同的标识符 #define 或类型定义是否被认为是可接受的做法?
- 是否可能有一个变量是对具有不同类标识符的模板类的引用?
- 是否有一种方法可以禁用C头文件中的全局标识符
- 是否可以仅通过标识符检查成员模板的存在
- c++中标识符名称的长度是否有限制?