提问人:earthmessenger 提问时间:7/2/2023 更新时间:7/2/2023 访问量:92
在 C++ 中使用 T1 = 无符号 T2 的奇怪结果
Strange result of using T1 = unsigned T2 in C++
问:
下面的代码让我感到困惑。
https://godbolt.org/z/WcMTYM1q7
#include <iostream>
using ll = long long;
using ull = unsigned ll;
int main() {
ull x = 0;
std::cout << x << std::endl;
}
此代码在 g++ 11 中编译失败,但在 g++ 12 和 g++ 13 中成功编译。在 g++ 11 中,编译器说:
error: ambiguous overload for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'ull' {aka 'long unsigned int'})
我还测试了以下代码。
https://godbolt.org/z/PrePfoa6E
#include <iostream>
using ll = long long;
using ull = unsigned ll;
using ull2 = std::make_unsigned_t<ll>;
int main() {
std::cout << typeid(ll).name() << std::endl;
std::cout << typeid(ull).name() << std::endl;
std::cout << typeid(ull2).name() << std::endl;
}
使用 g++ 13 编译代码时,它会打印 和 ,这意味着 和 。当使用 g++ 11 编译代码时,它会打印 、 和 ,这意味着 和 。总而言之,不是预期的类型。x
j
y
long long
unsigned int
unsigned long long
x
m
y
long long
unsigned long
unsigned long long
unsigned ll
为什么会这样?是编译器错误吗?我应该什么时候使用?std::make_unsigned
答:
using ull = unsigned ll;
不是有效的标准 C++。您不能将类型说明符(如)添加到 typedef 名称(如 .这仅适用于 cv 限定符,即 和 ,而不是其他更改类型的限定符,例如 。unsigned
ll
const
volatile
unsigned
编译器应为此代码发出诊断程序,并且 GCC 使用 或 正确地执行此操作。-pedantic
-pedantic-errors
它完全没有这些标志进行编译,但不使用它们,这表明接受此声明可能是一种有意的不符合标准的行为,在这种情况下,没有理由假设没有文档说明这一点。unsigned ll
unsigned long long
文档提到,在 K&R C 中允许这种语法,但在 ISO C 中不允许,据推测,这是为了 K&R C 兼容性而保留的,并且不存在,因此这种语法似乎没有按预期实现这些类型。而 C++11 声明基本上只是 的语法糖 ,所以行为可能是从行为中获取的,即使它对兼容性没有意义。 强制执行标准一致性,以便不再允许此兼容性功能。typedef
long long
unsigned long long
using
typedef
typedef
-pedantic-errors
但是,无论哪种方式,GCC 11 的过载解决失败对我来说都是无意的,并且可以解释为更高版本中修复的错误。
这是一个编译器错误。
我不知道为什么 GCC 会编译这个,但绝对是格式错误的代码。
重载解决失败是允许此声明的结果,因为通常声明为:、 或 all work。
将其声明为会产生某种损坏的类型,而这些类型实际上不是其中任何一个。unsigned ll
ull
unsigned
unsigned long
unsigned long long
unsinged ll
using ull = unsigned ll;
Clang 拒绝了它,因为它应该:
<source>:4:22: error: type-id cannot have a name
using ull = unsigned ll;
^~
MSVC 也是如此:
<source>(4): error C2187: syntax error: 'll' was unexpected here
通常,只能在说明符列表中与(隐式)结合使用。您必须使用 ,否则此代码格式不正确。unsigned
int
std::make_unsigned_t<ll>
您仍然可以通过添加以下标志来使 GCC 拒绝此操作:
-Wpedantic -Werror
# or
-pedantic-errors
评论
std::make_unsigned
?”每当您需要某种类型的无符号版本时。您可能会问自己,如果效果很好,为什么还要费心添加到库中呢?std::make_unsigned_t<x>
unsigned x