简体   繁体   English

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

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

Except in a declaration of a constructor, destructor, or conversion function, at least one defining-type-specifier that is not a cv-qualifier shall appear in a complete type-specifier-seq or a complete decl-specifier-seq .除了在构造函数、析构函数或转换 function 的声明中,至少一个不是 cv-qualifier 的定义类型说明符应出现在完整的类型说明符序列或完整的decl-说明符序列中

Constructor is an exception because constructor can be declared like constructor(){} , No defining-type-specifier in this declaration, similarly for destructor.构造函数是一个例外,因为构造函数可以像constructor(){}一样声明,此声明中没有定义类型说明符,对于析构函数也是如此。

For conversion function , I can't have a idea that a conversion function does not need a type-specifier when I think in the above quote, defining-type-specifier contains type-specifier , because the sentence defining-type-specifier that is not a cv-qualifier implies that, only type-specifier contains cv-qualifier, Hence I think a conversion function declaration shall contain at least a defining-type-specifier (in less range, it's type-specifier that is a subset of defining-type-specifier), The grammar of a conversion function likes as the following, due to[dcl.fct.def#general-1] :对于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) function-body attribute-specifier-seq(opt) decl-specifier-seq(opt) declarator virt-specifier-seq(opt) 函数体

Thereof, its declarator will like as the following:其中,它的声明符如下所示:

operator conversion-type-id运算符转换类型 ID

conversion-type-id转换类型 ID

type-specifier-seq conversion-declarator(opt)类型说明符序列转换声明符(选择)

However according to [class.conv.fct] , It says:但是根据[class.conv.fct] ,它说:

A decl-specifier in the decl-specifier-seq of a conversion function (if any) shall be neither a defining-type-specifier nor static.转换 function(如果有)的decl-specifier-seq中的 decl-specifier 既不是定义类型说明符,也不是 static。

It means the decl-specifier-seq(opt) can't be a defining-type-specifier nor static.这意味着decl-specifier-seq(opt)不能是定义类型说明符,也不能是 static。

But, in the type-specifier-seq of a conversion-type-id, It must be a defining-type-specifier.但是,在转换类型标识的类型说明符序列中,它必须是定义类型说明符。

operator Type(){  // Type is a defining-type-specifier(more exactly,it's a type-specifier)
  return Type{};
}

and you wouldn't define a conversion functions like this:而且您不会像这样定义转换函数:

operator (){ // there's no defining-type-specifier in type-specifier-seq
  //...
}

[dcl.fct#11] [dcl.fct#11]

Types shall not be defined in return or parameter types.类型不应在返回或参数类型中定义。

This is a restriction for that the defining-type-specifier must appear in a function declaration, Due to这是定义类型说明符必须出现在 function 声明中的限制,由于

defining-type-specifier consists of:定义类型说明符包括:

  • type-specifier类型说明符
  • class-specifier类说明符
  • enum-specifier枚举说明符

class-specifier or enum-specifier can't be used in a decl-specifier-seq of a function delcaration because of the last quote.由于最后一个引号, class-specifierenum-specifier不能用于 function 声明的 decl-specifier-seq 中。 only type-specifier is permitted.只允许type-specifier

So, as far as now, what the standard actually wants to say is that, use a more range wording for type-specifier , namely, defining-type-specifier , because you indeed can declare a variable likes struct A{} variable;因此,就目前而言,该标准实际上想说的是,对type-specifier使用更广泛的措辞,即definition-type-specifier ,因为您确实可以声明一个变量,如struct A{} variable; , there's no class-specifier be contained in type-specifier, hence, as a general rule, the standard use the "wording" defining-type-specifier to cover such cases. ,类型说明符中不包含类说明符,因此,作为一般规则,标准使用“措辞”定义类型说明符来涵盖此类情况。

So, why conversion function is an exception in the first rule?那么,为什么转换 function 在第一条规则中是一个例外? If there're any misunderstandings in the above analysis, correct me.以上分析如有误会,敬请指正。

Questions:问题:

  1. why a conversion function is an exception in the first quote?为什么转换 function 在第一个报价中是一个例外?
  2. If a conversion function is an exception, why other functions are not?如果一个转换 function 是一个例外,为什么其他功能没有呢?

A function declaration must have a defining-type-specifier simply means that a function declaration must have the form: function 声明必须具有定义类型说明符仅意味着 function 声明必须具有以下形式:

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

and can't be of the form:并且不能是以下形式:

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

The quoted rule from dcl.fct :来自dcl.fct的引用规则:

Types shall not be defined in return or parameter types.类型不应在返回或参数类型中定义。

has nothing to do with defining-type-specifiers (despite the similar terminology).定义类型说明符无关(尽管术语相似)。 It simply means that you can't define a type in the declaration of a function.它只是意味着您不能在 function 的声明中定义类型。

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

so this is not in conflict with the exceptions quoted at the beginning of your question.所以这与您问题开头引用的例外情况并不冲突。

I agree - the paragraph [dcl.type]/3 should instead say something like:我同意 - 段落[dcl.type]/3应该改为:

Except in a declaration of a constructor, destructor, or conversion function, or in a lambda-declarator , a complete decl-specifier-seq shall contain at least one defining-type-specifier that is not a cv-qualifier .除了在构造函数、析构函数或转换 function 或lambda-declarator 的声明中,完整的decl-specifier-seq应包含至少一个不是cv-qualifier定义类型说明符 A complete type-specifier-seq shall contain at least one type-specifier that is not a cv-qualifier .完整的 type-specifier-seq应包含至少一个不是cv-qualifier类型说明符

You're correct that:你是对的:

  • defining-type-specifier parses a wider set of input token sequences than type-specifier . definition-type-specifier解析比type-specifier更广泛的输入标记序列集。
  • decl-type-specifier parses an even wider set of input token sequences than defining-type-specifier . decl-type-specifier解析比defined -type-specifier 更广泛的输入标记序列集。
  • const and volatile are valid in parsing any of the three. constvolatile在解析这三者中的任何一个时都是有效的。
  • The syntaxes including class ClassName { ... };语法包括class ClassName { ... }; and enum EnumName { ... };enum EnumName { ... }; are valid in a defining-type-specifier or a decl-type-specifier but not in a type-specifier .定义类型说明符声明类型说明符中有效,但在类型说明符中无效。

The C++ grammar uses type-specifier-seq and decl-specifier-seq in many places where the name of a type is expected (plus a few where they're not to name a type). C++ 语法在许多需要类型名称的地方使用type-specifier-seqdecl-specifier-seq (加上一些不命名类型的地方)。 The quoted paragraph [dcl.type]/3 requiring "at least one defining-type-specifier that is not a cv-qualifier " in these sequences is mainly saying that in all of those contexts, variations which don't name a type at all are not permitted: you can't say auto v1 = new const;引用的段落[dcl.type]/3要求在这些序列中“至少有一个不是cv 限定符的定义类型说明符”主要是说在所有这些上下文中,没有在都不允许:你不能说auto v1 = new const; or static constexpr typedef f();static constexpr typedef f(); . . Most individual uses have additional restrictions on what sorts of type-specifier can and cannot appear there, but those such rules are in addition to this basic one.大多数个人用途对哪些类型的类型说明符可以出现和不能出现在那里有额外的限制,但这些规则是对这个基本规则的补充。 In particular, many of them don't allow defining types within the specifier sequence.特别是,它们中的许多不允许在说明符序列中定义类型。 But since decl-type-specifier is used within simple-declaration as the ordinary way to define classes and enumerations, this rule is not the place for that restriction.但是由于decl-type-specifiersimple-declaration中用作定义类和枚举的普通方式,因此该规则不适用于该限制。

The reason for excluding constructors, destructors, and conversion functions is that although they might not have a decl-type-specifier-seq at all, they might in fact use a decl-type-specifier which does not contain any defining-type-specifier .排除构造函数、析构函数和转换函数的原因是,尽管它们可能根本没有decl-type-specifier-seq ,但实际上它们可能使用不包含任何定义类型说明符的decl-type -specifier . For example, in例如,在

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

the constructor declaration has a decl-type-specifier whose only specifier is the explicit keyword, which is not a defining-type-specifier .构造函数声明有一个decl-type-specifier ,其唯一的说明符是explicit关键字,它不是一个定义类型说明符

(However, in looking through, I found another context where the rule should NOT apply: A lambda expression allows an optional decl-specifier-seq after its parameter list, where the only permitted specifiers are mutable and constexpr ; neither is a defining-type-specifier .) (但是,通过查看,我发现了另一个不应该应用该规则的上下文:A lambda 表达式允许在其参数列表之后使用可选的decl-specifier-seq ,其中唯一允许的说明符是mutableconstexpr ;也不是定义类型-说明符。)

I'm guessing this paragraph version came along with or following a change in the grammar between C++14 and C++17.我猜这个段落版本是随着 C++14 和 C++17 之间的语法变化一起出现或出现的。 The initial decl-specifier-seq in a simple-declaration was changed from optional to required. simple-declaration中的初始decl-specifier-seq从可选更改为必需。 A new grammar symbol nodeclspec-function-declaration was added to cover cases of friend declarations and template-related declarations which declare constructors, destructors, or conversion functions with no initial specifiers and without defining them.添加了一个新的语法符号nodeclspec-function-declaration以涵盖友元声明和模板相关声明的情况,这些声明声明了没有初始说明符且未定义它们的构造函数、析构函数或转换函数。 Other declarations of constructors, destructors, and conversion functions are actually covered by either function-definition or member-declaration , which still use an optional decl-specifier-seq , so the changes to simple-declaration didn't affect them.构造函数、析构函数和转换函数的其他声明实际上由function-definitionmember-declaration覆盖,它们仍然使用可选的decl-specifier-seq ,因此对simple-declaration的更改不会影响它们。

For conversion functions, the text in [class.conv.fct]/1 saying对于转换函数, [class.conv.fct]/1中的文本说

A decl-specifier in the decl-specifier-seq of a conversion function (if any) shall be neither a defining-type-specifier nor static .转换 function(如果有)的decl -specifier-seq中的 decl-specifier 既不是定义类型说明符,也不是static

forms the actual requirement: The [dcl.type] sentence excludes a conversion function's decl-type-specifier-seq from its usual requirement, so it doesn't say anything about what is and isn't legal. forms 实际要求: [dcl.type] 语句将转换函数的decl-type-specifier-seq从其通常要求中排除,因此它没有说明什么是合法的,什么是不合法的。 This [class.conv.fct] sentence gives the actual rule for this case.这个 [class.conv.fct] 句子给出了这种情况的实际规则。

A conversion function may be declared:可以声明一个转换 function:

  • by a function-definition (if it has a body, including =default; or =delete; )通过函数定义(如果它有一个主体,包括=default;=delete;
  • by a member-declaration (inside a class definition, if the declaration does not have a body)通过成员声明(如果声明没有正文,则在 class 定义中)
  • by a simple-declaration or nodeclspec-function-declaration (if in a friend declaration, explicit specialization, or explicit instantiation)通过简单声明nodeclspec-function-declaration (如果在友元声明、显式特化或显式实例化中)

A nodeclspec-function-declaration allows no initial specifiers, but the other three symbols all have a rule in which a decl-specifier-seq (either required or optional) is followed by either a declarator or an init-declarator-list . nodeclspec-function-declaration不允许初始说明符,但其他三个符号都有一个规则,其中decl-specifier-seq (必需或可选)后跟declaratorinit-declarator-list As you noted, the declarator for a conversion function contains the operator keyword followed by a type-specifier-seq .如您所述,转换 function 的声明符包含operator关键字,后跟type-specifier-seq The declarator must also contain () or (void) or equivalent so that it declares a function with no arguments.声明符还必须包含()(void)或等效项,以便声明没有 arguments 的 function。

With a few more assumptions, the general form of a conversion function declaration is either再加上一些假设,转换 function 声明的一般形式是

attribute-specifier-seq opt decl-specifier-seq opt operator type-specifier-seq conversion-declarator opt attribute-specifier-seq opt parameters-and-qualifiers virt-specifier-seq opt pure-specifier opt ;属性-说明符-seq opt decl-specifier-seq opt operator type-specifier-seq conversion-declarator opt attribute-specifier-seq opt parameters-and-qualifiers virt-specifier-seq opt pure-specifier opt ;

or或者

attribute-specifier-seq opt decl-specifier-seq opt operator type-specifier-seq conversion-declarator opt attribute-specifier-seq opt parameters-and-qualifiers virt-specifier-seq opt function-body属性说明符序列opt decl 说明符 seq opt operator类型说明符 seq 转换声明符opt属性说明符 seq opt参数和限定符 virt 说明符 seq opt函数体

So there's an optional decl-specifier-seq before the operator keyword and a required type-specifier-seq after it.所以在operator关键字之前有一个可选的decl-specifier-seq ,在它之后有一个必需的type-specifier-seq It's the decl-specifier-seq which might not be present at all, and which must not contain a defining-type-specifier (because you don't put a type before the operator keyword) or static (because a conversion function must always be a non-static member).它是decl-specifier-seq可能根本不存在,并且不能包含定义类型说明符(因为您没有在operator关键字之前放置类型)或static (因为转换 function 必须始终为非静态成员)。 But the decl-specifier-seq may contain constexpr , inline , virtual , or explicit , or combinations of those.decl-specifier-seq可能包含constexprinlinevirtualexplicit或它们的组合。

The trouble you've noticed is that the wording of [dcl.type]/3 also means it technically doesn't apply to the type-specifier-seq in such a declaration which names the target type for the conversion.您注意到的问题是 [dcl.type]/3 的措辞也意味着它在技术上不适用于命名转换目标类型的声明中的type-specifier-seq ( [dcl.pre]/4 clears up many similar statements about grammar symbols in a declaration, but doesn't apply to this case since there's no intervening scope involved.) We could still infer that a defining-type-specifier is needed from phrases in the Standard like "the type specified by the conversion-type-id ". [dcl.pre]/4在声明中清除了许多关于语法符号的类似陈述,但不适用于这种情况,因为没有涉及 scope 的干预。)我们仍然可以推断出需要定义类型说明符标准中的短语,例如“由转换类型 ID 指定的类型”。 But it would be better if the rule in [dcl.type]/3 applied to this type-specifier-seq like it does to most of them.但是,如果 [dcl.type]/3 中的规则适用于这个type-specifier-seq会更好,就像它对它们中的大多数一样。

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

相关问题 为什么我的模板化函数需要从一个迭代器到另一个迭代器的转换? - Why does my templated function require a conversion from one iterator to the other? 如果在其他地方声明为const,为什么必须在定义时重复const说明符? - Why does one have to repeat the const specifier at definition time, if declaration as const is done somewhere else? 在一个声明语句中定义函数和变量 - Defining a function and a variable in one declaration statement 友元函数声明中的内联说明符 - inline specifier in a friend function declaration 使用“自动”的声明是否与使用具体类型说明符的外部声明匹配? - Does a declaration using “auto” match an extern declaration that uses a concrete type specifier? 如何显式调用转换类型 ID 包含占位符说明符的转换 function - How to explicitly call a conversion function whose conversion-type-id contains a placeholder specifier 该声明没有存储类或类型说明符 - this declaration has no storage class or type specifier 构造函数声明中的“缺少类型说明符”错误 - “missing type specifier” error on constructor declaration 错误:此声明没有存储或类型说明符 - Error: this declaration has no storage or type specifier 错误“此声明没有存储类或类型说明符” - Error “this declaration has no storage class or type specifier”
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM