一元加运算符的作用是什么?


86

一元加运算符的作用是什么?我已经找到了几个定义(在这里这里),但是我仍然不知道它将用于什么目的。似乎它什么也没做,但是有一定理由,对吧?


3
我认为历史原因被严重低估了。
狼”

3
具有三种不同语言标签的问题非常含糊/不好!对于C#(可重载),C(无重载)和C ++(可重载,但从C继承并因此继承其属性)的答案也大不相同。
legends2k

我想添加一个链接到Eric Lippert的C#的十大缺陷。您会在荣誉奖中找到一元加运算符:notifyit.com/articles/article.aspx?p=2425867他基本上说应该删除它,或者永远不要添加它。
Noel Widmer

Answers:


57

如果您感到有需要,那将是超负荷的;对于所有预定义的类型,它本质上是无操作的。

无操作数一元算术运算符的实际使用受到很大限制,并且往往与在算术表达式中使用值而不是运算符本身有关。例如,它可用于强制从较小的整数类型扩展为int,或确保将表达式的结果视为rvalue并因此与非const参考参数不兼容。但是,我认为这些用途比可读性更适合于编码高尔夫球。:-)


7
事实并非如此,如以下几个示例所示。
jkerian

3
好的,我会买它有一些用途,但是下面讨论的大多数用途都与它是使用无操作符构建的数值表达式有关的事实:例如,提升int并产生右值是表达式的效果-ness,而不是+运算符本身。
杰弗里·汉汀

118

实际上,一元加号确实可以执行某些操作-即使在C语言中也是如此。它对操作数执行常规的算术转换,并返回一个新值,该值可以是更大宽度的整数。如果原始值是一个宽度小于的无符号整数int,则它也将更改为一个signed值。

通常,这并不重要,但是产生影响,因此,使用一元加号作为表示整数为正数的“注释”并不是一个好主意。考虑以下C ++程序:

void foo(unsigned short x)
{
 std::cout << "x is an unsigned short" << std::endl;
}

void foo(int x)
{
 std::cout << "x is an int" << std::endl;
}

int main()
{
 unsigned short x = 5;
 foo(+x);
}

这将显示“ x是一个整数”。

因此,在此示例中,一元加号创建了具有不同类型符号的新值。


5
如果您编写的代码在给定short和一个int相等时会产生给定结果,那么您可能会有不同的问题
Lie Ryan

1
谢谢,这很清楚(旁注:在C中,由于无法重载foo函数,因此我无法运行该示例)
Binarian

说什么意思an integer of greater width
yekanchi '19

在这种情况下,“宽度”是指与该值关联的存储字节数。
giles

41

从K&R第二版:

一元+是ANSI标准的新功能。它是为与一元符号对称而添加的。


6
绝对。*这是历史原因。C ++必须适应它,因此它必须处理重载。
狼”

37

我看过它是为了清楚起见,强调正值不同于负值:

shift(+1);
shift(-1);

但这是一个很弱的用途。答案肯定是超载。


8
我也这样做了,尤其是在处理像vec3(+1,-1,-1)
mpen

28

内置一元代码+所做的一件事就是将左值变成右值。例如,您可以这样做

int x;
&x;

但是你做不到

&+x;

:)

PS“超载”绝对不是正确的答案。一元语言+是从C继承的,C中没有用户级的运算符重载。


14

一元+完成的主要工作是将类型升级为小于int的数据类型。如果您尝试将char数据std::cout用作数字数据来打印,这将非常有用。

char x = 5;
std::cout << +x << "\n";

char x=5;
std::cout << x << "\n";

它也可用于重载,但实际上,您的重载应该几乎是NOP。


12

如果出于调试或任何原因需要打印原始字节的数字值(例如,存储为char的小数字),则一元+可以简化打印代码。考虑

char c = 42;
cout << c << endl;           // prints "*\n", not what you want in this case
cout << (int)c << endl;      // prints "42\n", ok
cout << +c << endl;          // prints "42\n", much easier to type

这只是一个简单的例子。我敢肯定,在其他情况下,一元+可以帮助您将字节更像数字而不是文本。


4

历史花絮。C99标准化委员会还认为一元加号的现有用法很少见,这是由他们考虑重新使用它来实现该语言的另一个功能所证明的:禁止对浮点常量表达进行翻译时评估。请参见C原理的以下引言,第F.7.4节:

该规范的早期版本允许翻译时常量算术运算,但在将一元+运算符应用于操作数时,可以禁止对常量表达式的翻译时求值。

最后,语义被颠倒了,在大多数情况下(至少直到“好像”规则为止)都强制执行了运行时评估,并且通过使用静态初始化程序强制执行了翻译时评估。请注意,主要区别在于出现浮点异常以及其他浮点舍入或精度设置(如果存在)。


3

不多。允许重载的一般论点operator+()是,确实存在重载的实际用途,如果您允许重载但不允许重载operator-(),那将是奇怪的(或不对称的)。operator-()operator+()

我相信我首先从Stroustrop读了这个论点,但是我没有随身携带的书来验证它。我可能错了。


3

C语言中存在一元加号,它完全不执行任何操作(非常类似于auto关键字)。为了没有它,Stroustrup将不得不引入与C的不必要的不​​兼容。

一旦用C ++编写,就很自然地允许重载函数,就像一元减号一样,并且Stroustrup可能由于这个原因而引入了它(如果还没有的话)。

因此,它没有任何意义。它可以用作装饰,使事物看起来更对称,例如,使用+1.5表示与-1.5相反。在C ++中,它可以被重载,但是如果operator+()执行任何操作,将会造成混乱。记住标准规则:重载算术运算符时,请像ints那样做。

如果您正在寻找它存在的原因,请找到有关C早期历史的一些信息。我怀疑没有充分的理由,因为C并不是真正设计出来的。考虑一下无用的auto关键字(大概与相对static,现在在C ++ 0x中被回收)和entry没有做任何事情的关键字(后来在C90中被省略)。里奇(Ritchie)或克尼根(Kernighan)在一封著名的电子邮件中说,当他们意识到操作员优先级出现问题时,已经有三个安装了成千上万行代码的设备,他们不想破坏。


1
我见过的唯一有意义的非算术重载是在正则表达式或语法中,其中(+ term)表示一个或多个tems。(这是相当标准的正则表达式语法)
Michael Anderson

关于entry:(stackoverflow.com/q/254395/153285)。如今,如果您想要多个入口点,只需使用尾部调用和配置文件引导的优化即可。
Potatoswatter 2010年

我相信,即使在给定的C99中,给出extern volatile int foo;语句的编译器+foo;也将需要在可能存在任何手段确定读取发生的任何平台上执行对指定地址的读取。我不确定如果语句只是“ foo”是否需要,尽管许多编译器会出于礼貌使用它。
supercat 2015年

2

我无法提供任何来源,但是我已经了解它是用于显式类型提升,这意味着无损类型转换。这使它位于转换层次结构的顶部,

  • 促销: new_type operator+(old_type)
  • 转换: new_type(old_type)
  • 投: operator(new_type)(old_type)
  • 强迫: new_type operator=(old_type)

当然,这是根据我对大约15年前阅读的一本Microsoft(真的很老)的c / c ++手册中的注释的解释而得出的,因此请耐心等待。


1
#include <stdio.h>
int main()
{
    unsigned short x = 5;
    printf ("%d\n",sizeof(+x)); 
    printf ("%d\n",sizeof(x)); 
    return 0;
}

如上例所示,一元+确实分别更改了类型,大小4和2。很奇怪,表达式+ x的确是按sizeof计算的,我认为这是不应该的。可能是由于sizeof与一元+具有相同的优先级。


-1

我想您可以使用它使数字始终为正。只需重载一元+运算符即可。除非您真的只想混淆代码,否则不要真的让您的开发人员感到困惑。这样就可以了。


那将使其与一元负号相反,后者会引起混淆,除非您也将一元负号超载为负数绝对值,这将使各种数学问题变得
更糟

嗯是的 这就是为什么我建议不要这样做。
Patrick

1
@ Davy8:是什么让您认为一元加号当前是一元减号的“对立面”?按位补运算符的“对立”是~什么?我不确定您对“对立”的定义是什么,但我怀疑一元加法和一元减法当前的经验会给它带来偏差。
ndkrempel

-1

编辑完全重写,因为我原来的答案是waaaayyy。

这应该使您可以将类型的显式声明作为正值来处理(我认为在大多数非数学运算中)。似乎否定会更有用,但是我想这是一个可能会有所作为的示例:

public struct Acceleration
{
    private readonly decimal rate;
    private readonly Vector vector;

    public Acceleration(decimal rate, Vector vector)
    {
        this.vector = vector;
        this.rate = rate;
    }

    public static Acceleration operator +(Acceleration other)
    {
        if (other.Vector.Z >= 0)
        {
            return other;
        }
        return new Acceleration(other.Rate, new Vector(other.vector.X, other.Vector.Y, -other.vector.Z));
    }

    public static Acceleration operator -(Acceleration other)
    {
        if (other.Vector.Z <= 0)
        {
            return other;
        }
        return new Acceleration(other.Rate, new Vector(other.vector.X, other.Vector.Y, -other.vector.Z));
    }

    public decimal Rate
    {
        get { return rate; }
    }

    public Vector Vector
    {
        get { return vector; }
    }
}

在我看来,这似乎不是一元的操作。它需要两个参数(4月和5月),所以将是二进制的。
BlueMonkMN

那是二进制的。一元加号只是“ +1”或类似的值,没有左操作数。
Jeffrey Hantin

我的错。忘记了我的CS101。固定。
Michael Meadows,2009年

3
如果我在生产代码中发现了这种重载,那么我肯定会将其标记为错误并尽快修复。的语义+不是使值成为正数,而是使其符号保持不变。
Arturo TorresSánchez2015年

-1

只是用来说服哪些数字为正

例如;

int a=10;
System.out.println(+x);// prints 10(that means,that number 10 multiply by +1,{10*+1})

//if we use unary minus

int a=10;
System.out.println(-x);//prints -10(that means,that number 10 multiply by +1,{10*-1})
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.