为什么此代码不适用于 -m32?

Why this code didn't work for -m32?

#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;
}

我有一段代码可以通过 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

这段代码有什么问题?

您的代码是正确的。显然,既然警告只是警告。它指向一个事实,即比较涉及两个不相关的枚举,因此可能不明智。

如果您对分析感兴趣:
由于您正在针对 x86-32 进行编译,因此 sizeof(void*) 是 4。因此 a<> 指的是 a<4>,随后 a<4>::b 指的是一个枚举器。

所以表达式语句

a<>::b<c>d;

被解析为

(a<>::b < c) > d;

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

The usual arithmetic conversions are performed on operands of arithmetic or enumeration type. […]. After conversions, the operands shall have the same type.

(注意加粗部分,后面保证) [expr]/10:

This pattern is called the usual arithmetic conversions, which are defined as follows:

  • If either operand is of scoped enumeration type (7.2), no conversions are performed; if the other operand does not have the same type, the expression is ill-formed.
  • [ …Bullet points concerning floating point types… ]
  • Otherwise, the integral promotions (4.5) shall be performed on both operands. Then the following rules shall be applied to the promoted operands:
    • If both operands have the same type, no further conversion is needed.
    • […]

[conv.prom]/3:

中涵盖了普查员的积分提升

A prvalue of an unscoped enumeration type whose underlying type is not fixed (7.2) can be converted to a prvalue of the first of the following types that can represent all the values of the enumeration (i.e., the values in the range bmin to bmax as described in 7.2): int, unsigned int, long int, unsigned long int, long long int, or unsigned long long int.

两个操作数都提升为int后,表达式的结果为false(因为0不小于0)。

然后将此提升的结果与 d 进行比较 - 此处,d 如上所述提升为 int,而比较的结果 - 这是类型bool - 也提升为 int。 [conv.prom]/6:

A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true becoming one.

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

的值

您的代码编译没有错误,实际错误发生在链接时。链接器很可能无法找到 32 位版本 的运行时库。你有没有在你的系统上安装它们?