为什么这段代码不能用于-m32?

m0n*_*awk -1 c++ templates g++ 32bit-64bit

#include <stddef.h>

template<size_t N = sizeof(void*)> struct a;

template<> struct a<4> {
    enum { b };
};

template<> struct a<8> {
    template<int> struct b {};
};

enum { c, d };

int main() {
    a<>::b<c>d;
    d;
}
Run Code Online (Sandbox Code Playgroud)

我有一段代码可以通过gcc成功编译x64架构.但是-m32错误地失败了:

$ g++ -m32 test.cpp 
test.cpp: In function ‘int main()’:
test.cpp:16:12: warning: comparison between ‘enum a<4u>::<anonymous>’ and ‘enum<anonymous>’ [-Wenum-compare]
     a<>::b<c>d;
            ^
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

这段代码出了什么问题?

Col*_*mbo 8

你的代码是正确的.很明显,因为警告只是一个警告.它指的是这种比较涉及两个不相关的枚举,因此可能不合理.

如果您对分析感兴趣:
因为您正在为x86-32进行编译,sizeof(void*)所以是4.所以a<>引用a<4>,然后a<4>::b引用一个枚举器.

所以表达式声明

a<>::b<c>d;
Run Code Online (Sandbox Code Playgroud)

被解析为

(a<>::b < c) > d;
Run Code Online (Sandbox Code Playgroud)

现在执行通常的算术转换,在此期间int使用整数提升规则将两个操作数提升.[expr.rel]/2:

通常的算术转换是在算术或枚举类型的操作数上执行的.[...].转换后,操作数应具有相同的类型.

(注意粗体部分,稍后会确保.)[expr]/10:

此模式称为通常的算术转换,其定义如下:

  • 如果任一操作数具有作用域枚举类型(7.2),则不执行任何转换; 如果另一个操作数的类型不同,则表达式格式不正确.
  • [......关于浮点类型的子弹点...]
  • 否则,应对两个操作数执行整体促销(4.5).然后,以下规则应适用于提升的操作数:
    • 如果两个操作数具有相同的类型,则不需要进一步转换.
    • [...]

[conv.prom]/3涵盖了普查员的整体推广:

其基础类型未固定的无范围枚举类型的prvalue(7.2)可以转换为以下第一种类型的prvalue,它们可以表示枚举的所有值(即b minb范围内的值)最大为7.2所述): , int,unsigned int,long int,unsigned long int,long long intunsigned long long int.

在两个操作数被提升之后int,表达式的结果是false(因为0不小于0).

然后比较这个促销的结果d- 这里,如上所述d被提升int,而比较的结果 - 类型bool- 也被提升int.[conv.prom]/6:

类型的prvalue bool可以转换为类型的prvalue int, false变为零并true成为一个.

所以两个操作数都有类型int.第二个外部比较产生true,因为false- > 0小于1,值d.