【问题标题】:why a conversion function declaration does not require at least one defining-type-specifier为什么转换函数声明不需要至少一个定义类型说明符
【发布时间】:2020-06-22 02:01:57
【问题描述】:

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

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

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

attribute-specifier-seq(opt) decl-specifier-seq(opt) 声明符 virt-specifier-seq(opt) function-body

其中,它的声明符如下:

运算符转换类型-id

转换类型 ID

type-specifier-seq 转换声明符(opt)

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

转换函数(如果有)的 decl-specifier-seq 中的 decl-specifier 既不是 defining-type-specifier 也不是静态的。

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

但是,在一个conversion-type-id的type-specifier-seq中,它必须是一个defining-type-specifier。

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]

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

这是因为定义类型说明符必须出现在函数声明中的限制,因为

定义类型说明符包括:

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

class-specifierenum-specifier 不能在函数声明的 decl-specifier-seq 中使用,因为最后一个引号。只允许type-specifier

所以,就目前而言,该标准实际上想说的是,对 type-specifier 使用 more range 措辞,即 defining -type-specifier,因为你确实可以声明像struct A{} variable;这样的变量,所以没有class-specifier包含在type-specifier中,因此,作为一般规则,标准使用涵盖此类情况的“措辞”定义类型说明符

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

问题:

  1. 为什么转换函数在第一个引号中是一个例外?
  2. 如果一个转换函数是异常,为什么其他函数不是?

【问题讨论】:

    标签: c++ c++17 language-lawyer


    【解决方案1】:

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

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

    你说得对:

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

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

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

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

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

    (但是,在浏览过程中,我发现了另一个不应该应用该规则的上下文: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 中的文字说

    转换函数(如果有)的decl-specifier-seq中的decl-specifier不应是定义类型说明符 em> 也不是static

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

    可以声明一个转换函数:

    • 函数定义(如果它有一个主体,包括=default;=delete;
    • 成员声明(在类定义中,如果声明没有主体)
    • simple-declarationnodeclspec-function-declaration(如果在友元声明、显式特化或显式实例化中)

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

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

    attribute-specifier-seqopt decl-specifier-seqopt operator type-specifier-seq conversion-declarator opt 属性说明符-seqopt 参数和限定符 virt-specifier-seqopt 纯说明符opt ;

    attribute-specifier-seqopt decl-specifier-seqopt operator type-specifier-seq conversion-declarator opt 属性说明符序列opt 参数和限定符 virt-说明符序列opt 函数体

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

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

    【讨论】:

    • 是的,[class.conv.fct] 中的规则用于限制 operator 之前的 decl-specifier-seq 的类型说明符,但是在类型说明符内 - seq 在operator 之后,它确实必须需要一个定义类型说明符(一组更广泛的类型说明符,因为函数声明中的规则限制说明符不得定义新类型),这是我的困惑,为什么转换函数不需要定义类型说明符,它与上述冲突。
    • 哦,我明白你的意思了!这看起来确实像一个错误:我很确定这并不是要排除 conversion-function-idtype-specifier-seq 用于一个转换函数声明,只有它的 decl-specifier-seq。由于[dcl.pre]/4,许多适用于“薄嵌套”语法符号但不适用于“深层嵌套”语法符号的规则是这样的,但不是这个,因为 declaratordecl-specifier-seq 在这种情况下。
    • 很高兴看到您明白我的意思,谢谢。那么,这可能是标准中的缺陷?
    • 已编辑。是的,我认为这是一个小缺陷。
    【解决方案2】:

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

       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的引用规则:

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

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

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

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

    【讨论】:

    • 如果你认为这个问题,那么函数和转换函数有什么区别,转换函数声明必须有一个定义类型说明符operator Type();,并且不能是@的形式987654327@, operator struct A{}();..., 就是不能在转换函数的声明中定义类型。那么为什么转换函数是第一条规则中提到的例外呢?
    猜你喜欢
    • 1970-01-01
    • 2012-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-16
    • 1970-01-01
    相关资源
    最近更新 更多