繁体   English   中英

为什么转换 function 声明不需要至少一个定义类型说明符

[英]why a conversion function declaration does not require at least one defining-type-specifier

除了在构造函数、析构函数或转换 function 的声明中,至少一个不是 cv-qualifier 的定义类型说明符应出现在完整的类型说明符序列或完整的decl-说明符序列中

构造函数是一个例外,因为构造函数可以像constructor(){}一样声明,此声明中没有定义类型说明符,对于析构函数也是如此。

对于conversion function ,我不知道转换 function 不需要类型说明符,当我在上面的引用中认为时, defining-type-specifier包含type-specifier ,因为句子定义类型说明符是不是 cv 限定符意味着,只有类型说明符包含 cv 限定符,因此我认为转换 function 声明应至少包含一个定义类型说明符(在较小的范围内,它的类型说明符是定义的子集-类型说明符),由于[dcl.fct.def#general-1] ,转换 function 的语法如下所示:

attribute-specifier-seq(opt) decl-specifier-seq(opt) declarator virt-specifier-seq(opt) 函数体

其中,它的声明符如下所示:

运算符转换类型 ID

转换类型 ID

类型说明符序列转换声明符(选择)

但是根据[class.conv.fct] ,它说:

转换 function(如果有)的decl-specifier-seq中的 decl-specifier 既不是定义类型说明符,也不是 static。

这意味着decl-specifier-seq(opt)不能是定义类型说明符,也不能是 static。

但是,在转换类型标识的类型说明符序列中,它必须是定义类型说明符。

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]

类型不应在返回或参数类型中定义。

这是定义类型说明符必须出现在 function 声明中的限制,由于

定义类型说明符包括:

  • 类型说明符
  • 类说明符
  • 枚举说明符

由于最后一个引号, class-specifierenum-specifier不能用于 function 声明的 decl-specifier-seq 中。 只允许type-specifier

因此,就目前而言,该标准实际上想说的是,对type-specifier使用更广泛的措辞,即definition-type-specifier ,因为您确实可以声明一个变量,如struct A{} variable; ,类型说明符中不包含类说明符,因此,作为一般规则,标准使用“措辞”定义类型说明符来涵盖此类情况。

那么,为什么转换 function 在第一条规则中是一个例外? 以上分析如有误会,敬请指正。

问题:

  1. 为什么转换 function 在第一个报价中是一个例外?
  2. 如果一个转换 function 是一个例外,为什么其他功能没有呢?

function 声明必须具有定义类型说明符仅意味着 function 声明必须具有以下形式:

   Type  f();
// ^^^^ defining-type-specifier (in this case, a type-specifier)
// this must be an existing type

并且不能是以下形式:

f(); // error, no defining-type-specifier

来自dcl.fct的引用规则:

类型不应在返回或参数类型中定义。

定义类型说明符无关(尽管术语相似)。 它只是意味着您不能在 function 的声明中定义类型。

struct A{} f(); // error, can't define a type in return
void f(struct A{}); // error, can't define a type in parameter

所以这与您问题开头引用的例外情况并不冲突。

我同意 - 段落[dcl.type]/3应该改为:

除了在构造函数、析构函数或转换 function 或lambda-declarator 的声明中,完整的decl-specifier-seq应包含至少一个不是cv-qualifier定义类型说明符 完整的 type-specifier-seq应包含至少一个不是cv-qualifier类型说明符

你是对的:

  • definition-type-specifier解析比type-specifier更广泛的输入标记序列集。
  • decl-type-specifier解析比defined -type-specifier 更广泛的输入标记序列集。
  • constvolatile在解析这三者中的任何一个时都是有效的。
  • 语法包括class ClassName { ... }; enum EnumName { ... }; 定义类型说明符声明类型说明符中有效,但在类型说明符中无效。

C++ 语法在许多需要类型名称的地方使用type-specifier-seqdecl-specifier-seq (加上一些不命名类型的地方)。 引用的段落[dcl.type]/3要求在这些序列中“至少有一个不是cv 限定符的定义类型说明符”主要是说在所有这些上下文中,没有在都不允许:你不能说auto v1 = new const; static constexpr typedef f(); . 大多数个人用途对哪些类型的类型说明符可以出现和不能出现在那里有额外的限制,但这些规则是对这个基本规则的补充。 特别是,它们中的许多不允许在说明符序列中定义类型。 但是由于decl-type-specifiersimple-declaration中用作定义类和枚举的普通方式,因此该规则不适用于该限制。

排除构造函数、析构函数和转换函数的原因是,尽管它们可能根本没有decl-type-specifier-seq ,但实际上它们可能使用不包含任何定义类型说明符的decl-type -specifier . 例如,在

class MyClass {
public:
  explicit MyClass(int);
};

构造函数声明有一个decl-type-specifier ,其唯一的说明符是explicit关键字,它不是一个定义类型说明符

(但是,通过查看,我发现了另一个不应该应用该规则的上下文:A lambda 表达式允许在其参数列表之后使用可选的decl-specifier-seq ,其中唯一允许的说明符是mutableconstexpr ;也不是定义类型-说明符。)

我猜这个段落版本是随着 C++14 和 C++17 之间的语法变化一起出现或出现的。 simple-declaration中的初始decl-specifier-seq从可选更改为必需。 添加了一个新的语法符号nodeclspec-function-declaration以涵盖友元声明和模板相关声明的情况,这些声明声明了没有初始说明符且未定义它们的构造函数、析构函数或转换函数。 构造函数、析构函数和转换函数的其他声明实际上由function-definitionmember-declaration覆盖,它们仍然使用可选的decl-specifier-seq ,因此对simple-declaration的更改不会影响它们。

对于转换函数, [class.conv.fct]/1中的文本说

转换 function(如果有)的decl -specifier-seq中的 decl-specifier 既不是定义类型说明符,也不是static

forms 实际要求: [dcl.type] 语句将转换函数的decl-type-specifier-seq从其通常要求中排除,因此它没有说明什么是合法的,什么是不合法的。 这个 [class.conv.fct] 句子给出了这种情况的实际规则。

可以声明一个转换 function:

  • 通过函数定义(如果它有一个主体,包括=default;=delete;
  • 通过成员声明(如果声明没有正文,则在 class 定义中)
  • 通过简单声明nodeclspec-function-declaration (如果在友元声明、显式特化或显式实例化中)

nodeclspec-function-declaration不允许初始说明符,但其他三个符号都有一个规则,其中decl-specifier-seq (必需或可选)后跟declaratorinit-declarator-list 如您所述,转换 function 的声明符包含operator关键字,后跟type-specifier-seq 声明符还必须包含()(void)或等效项,以便声明没有 arguments 的 function。

再加上一些假设,转换 function 声明的一般形式是

operator ; operator ;

或者

operator operator

所以在operator关键字之前有一个可选的decl-specifier-seq ,在它之后有一个必需的type-specifier-seq 它是decl-specifier-seq可能根本不存在,并且不能包含定义类型说明符(因为您没有在operator关键字之前放置类型)或static (因为转换 function 必须始终为非静态成员)。 decl-specifier-seq可能包含constexprinlinevirtualexplicit或它们的组合。

您注意到的问题是 [dcl.type]/3 的措辞也意味着它在技术上不适用于命名转换目标类型的声明中的type-specifier-seq [dcl.pre]/4在声明中清除了许多关于语法符号的类似陈述,但不适用于这种情况,因为没有涉及 scope 的干预。)我们仍然可以推断出需要定义类型说明符标准中的短语,例如“由转换类型 ID 指定的类型”。 但是,如果 [dcl.type]/3 中的规则适用于这个type-specifier-seq会更好,就像它对它们中的大多数一样。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM