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
,则会发出警告):
这不是扩展。在-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 引用