构造函数是一个异常(exception),因为构造函数可以像constructor(){}
一样声明,该声明中没有define-type-specifier,与析构函数类似。
对于conversion function
,当我在上述引用中认为defining-type-specifier
包含type-specifier
时,我不知道转换函数不需要类型说明符,因为句子 define-type-specifier不是cv限定词意味着,只有类型说明符包含cv-qualifier,因此,我认为转换函数声明应至少包含一个定义类型说明符(在较小范围内,它是类型定义符,它是define-type的子集-specifier),由于[dcl.fct.def#general-1],转换函数的语法如下所示:
因此,其声明者将如下所示:
但是根据[class.conv.fct],它说:
这意味着decl-specifier-seq(opt)
不能是定义类型说明符,也不能是静态的。
但是,在转换类型ID的类型说明符序列中,它必须是定义类型说明符。
operator Type(){ // Type is a defining-type-specifier(more exactly,it's a type-specifier)
return Type{};
}
并且您不会定义这样的转换函数:operator (){ // there's no defining-type-specifier in type-specifier-seq
//...
}
[dcl.fct#11]这是因为定义类型说明符必须出现在函数声明中的限制,由于
定义类型说明符包括:
由于最后一个引号,不能在函数delcaration的decl-specifier-seq中使用
class-specifier
或enum-specifier
。只允许使用type-specifier
。因此,到目前为止,该标准实际上要说的是,对类型说明符使用更多范围的措辞,即定义类型说明符,因为您确实可以声明一个像
struct A{} variable;
这样的变量,类型说明符中不包含类说明符,因此,作为一般规则,标准使用“措辞” 定义类型说明符来涵盖此类情况。那么,为什么转换函数是第一条规则中的异常(exception)?如果以上分析中有任何误解,请纠正我。
问题:
最佳答案
我同意-段落[dcl.type]/3应该改为:
您是正确的:
const
和volatile
在解析这三个中的任何一个时都是有效的。 class ClassName {
... };
和enum EnumName {
... };
的语法在define-type-specifier或decl-type-specifier中有效,但在type-specifier中无效。 C++ grammar在许多需要输入类型名称的地方使用type-specifier-seq和decl-specifier-seq(加上一些不使用类型命名的地方)。在这些序列中,带引号的[dcl.type]/3段落要求“至少一个不是cv限定词的define-type-specifier”主要是说在所有这些情况下,不允许根本不命名类型的变体:您不能说
auto v1 = new const;
或static constexpr typedef f();
。大多数个人用途对哪种类型的指定符可以出现在此处或不能出现在那里有附加的限制,但是这些规则是对这一基本规则的补充。特别是,其中许多不允许在说明符序列中定义类型。但是,由于在简单声明中使用了decl-type-specifier作为定义类和枚举的常规方法,因此该规则并不是该限制的地方。排除构造函数,析构函数和转换函数的原因是,尽管它们可能根本没有decl-type-specifier-seq,但实际上它们可能使用不包含任何定义类型-specifier的decl-type-specifier 。例如,在
class MyClass {
public:
explicit MyClass(int);
};
构造函数声明中有一个decl-type-specifier,其唯一的说明符是explicit
关键字,它不是define-type-specifier。(但是,在浏览过程中,我发现了另一个不适用于该规则的上下文:lambda表达式在其参数列表后允许一个可选的decl-specifier-seq,其中唯一允许的说明符为
mutable
和constexpr
;这两个都不是定义类型-说明符。)我猜想此段落版本是在C++ 14和C++ 17之间的语法中出现的或随之而来的。简单声明中的初始decl-specifier-seq已从可选更改为必需。添加了新的语法符号nodeclspec-function-declaration,以涵盖与好友声明和模板相关的声明的情况,这些声明声明了没有初始说明符且未定义它们的构造函数,析构函数或转换函数。构造函数,析构函数和转换函数的其他声明实际上都由function-definition或member-declaration覆盖,它们仍使用可选的decl-specifier-seq,因此对简单声明的更改不会影响它们。
对于转换功能,[class.conv.fct]/1中的文字说
形成实际需求:[dcl.type]语句从其通常需求中排除了转换函数的decl-type-specifier-seq,因此它没有说明什么是合法的。这个[class.conv.fct]句子给出了这种情况的实际规则。
可以声明一个转换函数:
=default;
或=delete;
)nodeclspec-function-declaration不允许使用任何初始说明符,但其他三个符号都有一条规则,其中decl-specifier-seq(必需或可选)后跟声明符或init-declarator-list。如您所述,转换函数的声明符包含
operator
关键字,后跟一个type-specifier-seq。声明程序还必须包含()
或(void)
或等效文件,以便声明不带参数的函数。再有一些假设,转换函数声明的一般形式是
要么
因此,在
operator
关键字之前有一个可选的decl-specifier-seq,在其后有一个必需的type-specifier-seq。它是decl-specifier-seq,可能根本不存在,并且绝对不能包含define-type-specifier(因为您没有在operator
关键字之前输入类型)或static
(因为转换函数必须始终为非静态成员)。但是decl-specifier-seq可能包含constexpr
,inline
,virtual
或explicit
或它们的组合。您已经注意到的麻烦是[dcl.type] / 3的措词在技术上也不适用于此类声明中的type-specifier-seq,该声明为转换指定了目标类型。 ([dcl.pre]/4清除了声明中有关语法符号的许多类似语句,但由于不涉及中间范围,因此不适用于这种情况。)我们仍然可以从标准中的短语中推断出需要一个define-type-specifier,例如“由conversion-type-id指定的类型”。但是如果[dcl.type] / 3中的规则像对大多数其他类型一样适用于此type-specifier-seq,那会更好。
关于c++ - 为什么转换函数声明不需要至少一个define-type-specifier,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/62506440/