【问题标题】:Strange construct & destructor syntax in GCC & clang (void* return type)GCC 和 clang 中的奇怪构造和析构函数语法(void* 返回类型)
【发布时间】:2018-11-04 08:39:30
【问题描述】:

在编写一些 C++ 代码(使用 clang、x86_64 linux 编译)时,我不小心写了以下构造:

class Class {
    *Class() {}
};

即在构造函数名称前带有星号 (*)。

尝试更多,我注意到您可以在前面放任意数量的 *;它也适用于析构函数,即,

class Class {
    ********Class() {}
    ********~Class() {}
};

Clang 编译它没有任何错误或警告。

但是 GCC 会给出警告

控制到达非空函数的结尾

这让我相信我实际上是在声明一个返回类型为void*(或void********)的构造函数/析构函数。并且用值编写任何类型的 return 语句都会产生错误(如预期的那样):

return nullptr;
return {};
...

有趣的是,生成的 LLVM IR 位码正确地包含了一个 void 函数:

define void @_ZN5ClassC2Ev(%struct.Class* %this) {...}
define void @_ZN5ClassD2Ev(%struct.Class* %this) {...}

搜索这方面的任何信息都没有找到任何结果。所以我的问题是:这个标准符合 C++ 还是 GCC 和 Clang 的编译器前端中的错误?或者也许是一些兼容性功能?如果正确,它的用例是什么。

【问题讨论】:

标签: c++ g++ clang clang++


【解决方案1】:

它看起来像一个错误。因为它不符合标准。声明或定义构造函数的标准方法是在[class.ctor]/1

构造函数没有名称。在构造函数的声明中, declarator 是表单的函数声明器

ptr-declarator (parameter-declaration-clause) noexcept-specifieropt attribute-specifier-seqopt

ptr-declarator 仅由一个 id-expression 组成,一个 可选的属性说明符序列和可选的环绕 括号,并且 id 表达式具有以下形式之一:

  • 在属于类的成员规范但不是友元声明的成员声明中,id 表达式是 立即封闭类的注入类名称;
  • 在属于类模板的成员规范但不是友元声明的成员声明中,id 表达式为 命名当前实例化的类名 立即封闭的类模板;或
  • 在命名空间范围内的声明或友元声明中,id-expression 是命名构造函数的限定 ID ([class.qual])。

类名不能是类型定义名。在构造函数中 声明,可选的 decl-specifier-seq 中的每个 decl-specifier 应该是friend、inline、explicit或constexpr。

正如您在我强调的部分中看到的那样,ptr-declarator 只能是一个 id 表达式。或者用更简单和不太准确的术语来说,它必须只是类名。

那么为什么可以在 Clang 和 GCC 中添加星号?看起来他们有一个错误,并且不要在这里对ptr-declarator 应用语义约束。这些约束很重要,因为纯语法确实允许使用星号。它在[dcl.decl]/4(仅部分复制):

声明符有语法

ptr 声明符: noptr 声明符 ptr 运算符 ptr 声明符 ptr 运算符: * 属性说明符序列opt cv 限定符序列opt & 属性说明符序列opt && 属性说明符序列opt 嵌套名称说明符 * 属性说明符序列opt cv-qualifier-seqopt

看到ptr-operator 的语法吗?就是说* 可以出现在您放置的位置。或者&,甚至&&。但是声明中的语义,我首先引用的那段,使它非法。

因此必须得出结论,这是 GCC 和 Clang 中的一个错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-02
    • 1970-01-01
    • 1970-01-01
    • 2015-07-02
    • 1970-01-01
    • 2020-09-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多