代码之家  ›  专栏  ›  技术社区  ›  xmh0511

为什么函数声明要求至少有一个定义类型说明符不是cv限定符

  •  0
  • xmh0511  · 技术社区  · 4 年前

    除非在构造函数、析构函数或转换函数的声明中,否则在完整的 类型说明符seq decl说明符序列 .

    构造函数是一个例外,因为构造函数可以像 constructor(){}

    conversion function ,我不知道转换函数不需要类型说明符, defining-type-specifier 包含 type-specifier 定义不是cv限定符的类型说明符 意味着,只有 类型说明符 定义类型说明符 (在较小的范围内,类型说明符是定义类型说明符的子集),由于 [dcl.fct.def#general-1] :

    其声明人如下:

    运算符转换类型id

    转换类型id

    转换声明符(opt)

    但是根据 [class.conv.fct] ,上面写着:

    中的decl说明符 转换函数(如有)的 也不是静态的。

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

    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-specifier enum-specifier 由于最后一个引号,无法在函数delcaration的decl说明符seq中使用。只有 类型说明符

    所以,到目前为止,标准真正想说的是,使用 更大范围 用词 定义类型说明符 struct A{} variable; 类说明符 包含在类型说明符中,因此,作为一般规则,标准使用“措辞” 来处理这类案件。

    问题:

    1. 为什么转换函数在第一个引号中是一个例外?
    2. 如果转换函数是例外,为什么其他函数不是?
    0 回复  |  直到 4 年前
        1
  •  1
  •   aschepler    4 年前

    [dcl.type]/3 应该这样说:

    除非在构造函数、析构函数或转换函数的声明中,或者在 ,一个完整的 decl说明符序列 cv限定符 . 完整的 类型说明符seq 应至少包含一个 类型说明符 cv限定符 .

    你说得对:

    • 定义类型说明符 类型说明符
    • decl类型说明符 解析比 定义类型说明符
    • const volatile
    • 语法包括 class ClassName { }; enum EnumName { 有效期为 或者 但不是在一个 类型说明符

    这个 C++ grammar 使用 类型说明符seq decl说明符序列 [dcl类型]/3 定义类型说明符 那不是一个好主意 cv限定符 auto v1 = new const; static constexpr typedef f(); 类型说明符 可以也不能出现在那里,但这些规则是对这个基本规则的补充。特别是,其中许多不允许在说明符序列中定义类型。但是自从 decl类型说明符 在中使用 作为定义类和枚举的普通方法,此规则不适用于该限制。

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

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

    唯一的说明符是 explicit 关键字,它不是 定义类型说明符 .

    (但是,在查看时,我发现了另一个不应该应用规则的上下文:lambda表达式允许可选的 decl说明符序列 mutable constexpr ;也不是 定义类型说明符 .)

    decl说明符序列 在一个 简单声明 已从可选更改为必需。一种新的语法符号 nodeclspec函数声明 是为了涵盖友元声明和模板相关声明的情况,这些声明声明构造函数、析构函数或转换函数没有初始说明符,也没有定义它们。构造函数、析构函数和转换函数的其他声明实际上包含在 会员声明 ,仍使用可选 decl说明符序列 ,所以 没有影响他们。

    [class.conv.fct]/1

    A decl说明符 decl说明符序列 转换函数(如有)的 也不是 static .

    形成实际需求[dcl类型]句子排除了转换函数的 decl类型说明符seq

    转换函数可以声明为:

    • 通过 (如有尸体,包括 =default; =delete;
    • (在类定义中,如果声明没有主体)
    • 通过 简单声明

    A nodeclspec函数声明 decl说明符序列 (必需或可选)后跟 或者一个 列表初始声明器 . 正如你所说的 因为转换函数包含 operator 类型说明符seq . 这个 声明人 还必须包含 () (void)

    属性说明符seq 选择 decl说明符序列 选择 类型说明符seq转换说明符 选择 选择 参数和限定符virt specifier seq 选择 纯说明符 选择 ;

    属性说明符seq 操作人员 选择 属性说明符seq 选择 参数和限定符virt specifier seq 选择 功能体

    操作人员 关键字和必填项 decl说明符序列 定义类型说明符 操作人员 静止的 (因为转换函数必须始终是非静态成员)。但是 可能包含 常量表达式 inline , virtual 明确的 ,或它们的组合。

    你注意到的问题是[dcl类型]/3也意味着技术上不适用于 类型说明符seq [dcl.pre]/4 清除声明中有关语法符号的许多类似语句,但不适用于本例,因为不涉及中间作用域) 转换类型id ". 但如果这条规则能被采纳就更好了[dcl类型]/3适用于此 类型说明符seq 就像大多数人一样。

        2
  •  2
  •   cigien Jorge Eldis    4 年前

    函数声明 必须 有一个 定义类型说明符 简单地说,函数声明必须具有以下形式:

       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
    

    因此,这与问题开头引用的例外情况并不冲突。