为什么'auto'不尊重一元减号运算符?

Why does 'auto' not respect the unary minus operator?

本文关键字:一元 运算符 auto 为什么      更新时间:2023-10-16

我对C++很陌生,但我发现auto的这种行为很奇怪:

class A{};
int main() {
A a;
auto x = -(sizeof(a));
cout << x << endl;
return 0;
}

在这种情况下,变量x是unsigned,尽管我在初始化变量时使用了一元减号运算符。为什么只考虑sizeof(std::size_t(的返回类型,而不考虑由于使用了运算符而存储的数字将为负数的事实?

我知道size_t是一个无符号整数

我已经在GCC 8.1.0和C++17中尝试过了。

这里的实际问题是,一元减号运算符的使用,就像其他内置算术运算符一样,是积分提升的主题。因此,令人惊讶的是,将一元负应用于size_t的结果仍然是size_t,并且没有必要责怪auto

反例。在这种情况下,由于整体促销,x的类型为int,因此输出为-1:

unsigned short a{1};
auto x{-a};
cout << x << endl;

表达式-(sizeof(a))将一元-运算符应用于无符号类型的值。一元运算符不会将无符号整数值转换为有符号整数值;它定义了哪个无符号值将是这样一个操作的结果,如下所示(参见cppreference.com上的一元算术运算符(:

内置的一元减号运算符计算其提升操作数。对于无符号a,-a的值为2^b-a、 其中b是提升之后的比特数。

因此,即使令人惊讶,auto也能正常工作,因为将一元-运算符应用于无符号值的结果仍然是无符号值。

应用于无符号值的(一元(-的结果为无符号,sizeof返回无符号值。

一元运算符的操作数应具有算术或无范围枚举类型,结果是其操作数的否定。对积分或枚举操作数执行积分提升。无符号量的负数是通过减去其2^n中的值,其中n是提升操作数中的位数。结果的类型是提升操作数的类型。

[expr.unary.op]

sizeofsizeof...的结果是类型为std​::​size_­t

[expr.sizeof]

为了避免实现定义的行为,在应用-之前,必须转换为int

如果目标类型已签名,则如果可以以目的地类型表示;否则,值为实现定义。

[conv.integral]

class A{};
int main() {
A a;
auto x = -(int{sizeof(a)});
cout << x << endl;
return 0;
}

如果我们看看:https://en.cppreference.com/w/cpp/language/sizeof,结果是类型size_t,即unsigned。您需要显式地将其声明为signed int以允许负值。

您可以编写允许负值的int,而不是auto