const 指向成员的指针是不是默认指向 int?

Posted

技术标签:

【中文标题】const 指向成员的指针是不是默认指向 int?【英文标题】:Does const pointer-to-member default to pointing to an int?const 指向成员的指针是否默认指向 int? 【发布时间】:2019-06-10 00:26:41 【问题描述】:

在使用指向成员的指针时,我遇到了一种行为,这种行为对我来说似乎有点不一致并且有点违反直觉。考虑以下虚拟结构:

struct foo 
    int x;
    double d;
;

还有以下main()

int main() 
    int foo::* ptr = &foo::x;
    double foo::* ptr2 = &foo::d;

这里我们没有什么异常 - 两个指向 const 成员的指针。代码编译正常。

引起我注意的是,当我们添加const 时,情况发生了一点变化。考虑以下代码:

int main() 
    // no int or double after const
    const foo::* ptr = &foo::x;

代码在 GCC 8.2.01 上编译良好。请注意,我没有指定指针将指向什么数据类型。

但是,这段代码:

int main() 
    // notice the only change - "d" instead of "x"
    const foo::* ptr = &foo::d;

编译失败,出现以下错误:

错误:无法在初始化 const foo::* ptr = &foo::d; 中将“double foo::*”转换为“const int foo::*

这很有趣 - 它表明,默认情况下,const 指向成员的指针被隐式声明为指向某个 int 成员。这是正确的标准行为吗?

值得注意的是,如果我们删除const,这两行都会产生错误:

int main() 
    foo::* ptr1 = &foo::x;
    foo::* ptr2 = &foo::d;

形式为:

错误:“*”令牌之前的预期不合格 ID

错误:'ptr1' | 'ptr2' 未在此范围内声明

所以问题是 - 如果我们没有另外指定,标准是否指定 const 指向成员的指针隐式指向 int,或者它是非标准行为? (GCC 扩展或 GCC 错误)。


1编辑:我正在使用 MinGW 的 GCC - this 特定版本。

【问题讨论】:

"代码在 GCC 8.2.0 上编译得很好" 嗯,不。 您是否使用-fpermissive 进行编译?我强烈建议不要这样做。 通常当没有给出类型时,假定为 int。我猜这就是为什么它可以工作的原因,或者更确切地说,对于 int,但不是 double。 @Chipster 我有其他建议吗?不打算。 @Chipster 啊是的,我知道,但是谢谢。 【参考方案1】:

ISO C++ 中的代码不正确,但 -fms-extensions 启用了“隐式 int”行为,gcc 自动启用该行为以针对 Microsoft ABI。

您可以使用-fno-ms-extensions 将其关闭。


我检查了源代码 (gcc-9.1.0/gcc/cp/decl.c),结果发现在ms-extensions 模式下,implicit int 的警告被禁用——任何东西会生成消息 ISO C++ forbids declaration of %qs with no type 实际上是被承认的,int 被用于类型。

这可能是一个比解决它试图解决的任何问题所需的更大的锤子。例如,您还可以看到与 const *x;const f(); 的差异。

我尝试将 -fno-ms-extensions 添加到我使用 mingw-w64 的一些“大型”Windows 项目的构建中并且没有出现错误,因此将这个标志作为一个习惯问题可能是一个好习惯(或者甚至向 mingw-w64 提交补丁以使其默认关闭...)。

【讨论】:

我将发布我的 Cygwin 错误报告的后续内容。我很失望,在默认启用-fms-extensions 的系统上,g++ -std=c++11 -pedantic 无法生成所需的诊断。我可能会向 gcc 提交一个错误。 有趣的是,gcc -fms-extensions 警告 C 中隐含的 int。您是否碰巧知道 MinGW 和其他 Windows 版本的默认选项是如何打开的?它是一个配置选项,还是他们修改了 gcc 源? (我正在尝试确定这是否是 gcc 错误。) @KeithThompson 您可以通过在 github 上找到 mingw-w64 项目来检查源代码。 AFAIK 他们根本不修改 gcc 源,但他们显然确实在某处打开了这个选项。我认为没有必要向 gcc 报告错误,因为这似乎是预期的行为,但是对ms-extensions 所做的事情进行更细粒度的控制可能会很好(例如,如果他们允许-Wimplicit-int 否决@ 987654336@。在推荐更改之前,需要熟悉用例;我不是。也许有一些流行的代码库需要这个标志。 如果它被识别为 System Header ,他们已经有一个过滤器不会发出警告,也许这不能正确识别 Windows 标题?谁知道呢。 @KeithThompson 进一步检查,发现标志控制在 GCC 源中;如果 Target ABI 是 Microsoft 的,它会启用它。【参考方案2】:

所以问题是 - 如果我们没有另外指定,标准是否指定 const 指向成员的指针隐式指向 int

没有。 GCC 通常会用简单的英语给你答案并拒绝编译(或者如果你使用-fpermissive,则会发出警告):

错误:ISO C++ 禁止声明没有类型的“ptr”

这不是扩展。在-fpermissive 模式下允许这样做,以保持非常旧的遗留代码可编译。

MinGW-w64 提供的 GCC 似乎没有捕捉到这个错误。不知道是不是故意的。

【讨论】:

问题是我编译没有 -fpermissive。它在 Godbolt 上确实失败了,但是在我的构建中(我正在使用 [这里] 的 MinGW - STL 的构建),即使没有编译器标志,它仍然可以正常编译。那么你认为这是 MinGW 的一个错误吗? @Fureeish,您绝对应该将其包含在问题中。我可以在我的 MinGW 的 GCC 8.1 上重现它。 @Fureeish 它也发生在我自己在 Linux 上构建的 mingw GCC (8.3.0) 交叉编译器上。似乎是一个一般的 mingw 问题(或更准确地说,mingw-w64。) @Fureeish 在 cmets 的问题下,您说“它实际上与 -fpermissive 一起编译,没有它就无法编译。” ,但现在你说它在没有 -fpermissive 的情况下编译;是哪个? @KeithThompson 这似乎是意料之中的。见 M.M 的回答。

以上是关于const 指向成员的指针是不是默认指向 int?的主要内容,如果未能解决你的问题,请参考以下文章

C++,成员函数返回对包含指向 const 对象的指针的向量的 const 引用

为啥我们不能定义一个指向 int 指针的低 + *** const 指针?

cpp

指向 const 指针(或指向 const 的指针)

const关键字与指针

const关键字和指针