-->

What does the unary plus operator do?

2020-01-23 07:22发布

问题:

What does the unary plus operator do? There are several definitions that I have found (here and here) but I still have no idea what it would be used for. It seems like it doesn't do anything but there has be a reason for it, right?

回答1:

It's there to be overloaded if you feel the need; for all predefined types it's essentially a no-op.

The practical uses of a no-op unary arithmetic operator are pretty limited, and tend to relate to the consequences of using a value in an arithmetic expression, rather than the operator itself. For example, it can be used to force widening from smaller integral types to int, or ensure that an expression's result is treated as an rvalue and therefore not compatible with a non-const reference parameter. I submit, however, that these uses are better suited to code golf than readability. :-)



回答2:

Actually, unary plus does do something - even in C. It performs the usual arithmetic conversions on the operand and returns a new value, which can be an integer of greater width. If the original value was an unsigned integer of lesser width than int, it will be changed to a signed value as well.

Usually this isn't that important, but it can have an effect, so it's not a good idea to use unary plus as a sort of "comment" denoting that an integer is positive. Consider the following C++ program:

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

This will display "x is an int".

So in this example unary plus created a new value with a different type and signedness.



回答3:

From K&R second edition:

The unary + is new with the ANSI standard. It was added for symmetry with the unary -.



回答4:

I've seen it used for clarity, to emphasize the positive value as distinct from a negative value:

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

But that's a pretty weak use. The answer is definitely overloading.



回答5:

One thing the built-in unary + does is turning lvalue into an rvalue. For example, you can do this

int x;
&x;

but you can't do this

&+x;

:)

P.S. "Overloading" is definitely not the right answer. Unary + was inherited from C and there's no user-level operator overloading in C.



回答6:

The main thing unary + accomplishes is type promotion to an int for smaller-than-int data types. This can be quite useful if you're trying to print char data using std::cout as numeric data.

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

is very different from

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

It's also available for overloading, but in practice your overload should be nearly a NOP.



回答7:

If you ever need to print the numeric value of raw bytes (eg, small numbers stored as char) for debug or whatever reason, unary + can simplify the print code. Consider

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

This is just a quick example. I am sure there are other times when unary + can help treat your bytes more like numbers instead of like text.



回答8:

A historical tidbit. The C99 standardization committee also thought existing uses of unary plus were fairly rare, as evidenced by their considering reusing it to achieve another feature in the language: inhibition of translation-time evaluation of floating-point constant expressions. See the following quote from the C Rationale, section F.7.4:

An early version of this specification allowed translation-time constant arithmetic, but empowered the unary + operator, when applied to an operand, to inhibit translation-time evaluation of constant expressions.

In the end, the semantics were reversed, with run-time evaluation enforced in most contexts (at least up to the "as if" rule), and the ability to enforce translation-time evaluation by the use of static initializers. Note that the main difference lies in the occurrence of floating point exceptions, and other floating point rounding or precision settings, where present.



回答9:

Not much. The general argument for allowing the overload of operator+() is that there are definitely real world uses for overloading operator-(), and it would be very weird (or asymmetrical) if you were to allow overloading operator-() but not operator+().

I believe that I first read this argument from Stroustrop, but I don't have my books with me right to verify it. I might be wrong.



回答10:

Unary plus was present in C, where it did absolutely nothing (much like the auto keyword). In order to not have it, Stroustrup would have had to introduce a gratuitous incompatibility with C.

Once it was in C++, it was natural to allow an overload function, just like unary minus, and Stroustrup might have introduced it for that reason if it wasn't already there.

So, it means nothing. It can be used as as sort of decoration to make things look more symmetrical, using +1.5 as the opposite to -1.5 for example. In C++, it can be overloaded, but it's going to be confusing if operator+() does anything. Remember the standard rule: when overloading arithmetic operators, do things like the ints do.

If you're looking for a reason why it's there, find something about the early history of C. I suspect there was no good reason, as C was not really designed. Consider the useless auto keyword (presumably in contrast to static, now being recycled in C++0x), and the entry keyword, which never did anything (and later omitted in C90). There's a famous email in which Ritchie or Kernighan say that, when they realized the operator precedence had problems, there were already three installations with thousands of lines of code that they didn't want to break.



回答11:

I can't cite any source for this, but I have come to understand it is for explicit type promotion, which implies lossless type conversion. That puts it at the top of the conversion hierarchy,

  • Promotion: new_type operator+(old_type)
  • Conversion: new_type(old_type)
  • Cast: operator(new_type)(old_type)
  • Coercion: new_type operator=(old_type)

Of course, that's from my interpretation of a note in one of the microsoft (really old) c/c++ manuals that I read about 15 years ago, so take it with a grain of salt.



回答12:

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

As shown in the example above, the unary + really changes the type, size 4 and 2 respectively. Weird that the expression +x is indeed calculated in the sizeof, I thought that was not supposed to. Perhaps it's due to the fact that sizeof has the same priority as the unary +.



回答13:

I suppose you could use it to always make a number positive. Just overload the unary + operator to be abs. Not really worth confusing your fellow developers, unless you really just want to obfuscate your code. Then it'd work nicely.



回答14:

simply that used to convince which numbers are positive

eg;

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})


回答15:

EDIT Rewrote completely, because I was waaaayyy off in my original answer.

This should allow you to handle the explicit declaration of your type as a positive value (I think in mostly non-mathematical operations). It seems that negation would be more useful, but I guess here's an example of where it might make a difference:

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