为什么此代码不适用于 -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
小于 1
,d
.
的值
您的代码编译没有错误,实际错误发生在链接时。链接器很可能无法找到 32 位版本 的运行时库。你有没有在你的系统上安装它们?
#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
, orunsigned 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 typeint
, withfalse
becoming zero andtrue
becoming one.
所以两个操作数的类型都是int
。第二次,外部比较产生 true
,因为 false
->0
小于 1
,d
.
您的代码编译没有错误,实际错误发生在链接时。链接器很可能无法找到 32 位版本 的运行时库。你有没有在你的系统上安装它们?