31

Was the unary + operator only included for symmetry with the unary - operator, or does it find some practical use in C++ code?

Searching here, I came across What is the purpose of the unary '+' operator in C?, but the only useful scenarios there involve preprocessor macros. Those are good to know, but they seem to be some less common situations, and involve macros. Are there any use cases involving more common C++ code?

Community
  • 1
  • 1
Masked Man
  • 1
  • 7
  • 40
  • 80
  • 7
    Mathematically? No. But it might find a use in operator overloading with classes. – ApproachingDarknessFish Jan 16 '13 at 19:05
  • 1
    @ValekHalfHeart: Yes, but any overload that does anything but `return *this;` will be seen as an abuse. – rodrigo Jan 16 '13 at 19:09
  • @rodrigo But could still provide a side effect on `this`, doesn't it? If this is good or useful DSL design is another question. – πάντα ῥεῖ Jan 16 '13 at 19:12
  • 1
    @ArneMertz: As nice as Boost.Spirit is, it is certainly a language abuse. Not that it takes any merit of it, but operator overloading was not designed to do this kind of things, as it is evident when you realize that you cannot change the operator precedence and your fancy new meanings for old operators are a bit loose (`cout << a & b;`, anyone?). – rodrigo Jan 16 '13 at 19:18
  • @ApproachingDarknessFish: it might find a use in operator overloading with classes. will you explain it by giving an example. – Destructor Oct 29 '15 at 14:57
  • @rodrigo, First, it is not about returning `*this` but also returning it by-copy. Second, there are more mundane uses than Boost.Spirit I have found for operator+, in particular for classes that are references (proxies) to values and not values themselves. See my example below. In other words, operator+ might not return exactly `*this` (i.e. "self") but can return something that has a value "equivalent" to "self". That is not an abuse, in the sense that it has a reasonable operator+ that is not exactly implemented as `return *this;`. – alfC Aug 30 '20 at 12:19

9 Answers9

34
char ch = 'a';
std::cout << ch << '\n';
std::cout << +ch << '\n';

The first insertion writes the character a to cout. The second insertion writes the numeric value of ch to cout. But that's a bit obscure; it relies on the compiler applying integral promotions for the + operator.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • Is the numeric value its ASCII equivalent? – David G Jan 16 '13 at 19:26
  • 1
    @David - with a compiler that uses ASCII, yes. For other encodings (rare), no. – Pete Becker Jan 16 '13 at 19:32
  • Doesn't seem to work for me -- http://stacked-crooked.com/view?id=235071220bc8ba0e688b4b58051e182d might these be the rare encodings? – David G Jan 16 '13 at 19:34
  • @David - don't know what's going on with your program, but 104 is the ASCII code for 'h'. Oh, sorry, I see there's an error in my code, which I've just fixed. Hope that didn't confuse you too much. – Pete Becker Jan 16 '13 at 19:56
  • For promotions - is there any advantage over the more clearly intentional cast? It may work, it may even be an idiom some people reuse, but as a reviewer I have to look and see if some code dropped out (and worry about precedence of unary `+` vs binary `+` vs `<<`) – Greg May 03 '23 at 02:23
21

Symmetry with unary - isn't entirely useless; it can be used for emphasis:

const int foo = -1;
const int bar = +1;

And an overloaded unary + can be used to denote an operation that yields the same logical value as its operand, while performing some non-trivial computation. (I've seen this done for type conversions in Ada, which permits unary +, but not conversions, to be overloaded.) I don't have a good C++ example to hand, and one could argue that it would be poor style. (Then again, I've seen plenty of rants about overloading <<.)

As for why C++ has it, it's probably largely for consistency with C, which added it with the 1989 ANSI standard. The C Rationale just says:

Unary plus was adopted by the C89 Committee from several implementations, for symmetry with unary minus.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
11

If you explicitly stay clear of any number value semantics for a class, any operator overloading is clear not to "do as the ints do". In that case, the unary plus may get any meaning, doing much more than just returning *this

Prominent example: Boost.Spirit's unary plus for the embedded EBNF's Kleene Plus generates a parser rule that lets it's argument (a parser rule as well) match one or more times.

Arne Mertz
  • 24,171
  • 3
  • 51
  • 90
5

The unary + operator turns a lvalue into an rvalue:

struct A {
  static const int value = 1;
};

// ...

int x = std::min(0, A::value);

Oh noes! This code won't link, because someone forgot to define (as well as declare) A::value. std::min takes its arguments by reference so A::value must have an address so a reference can bind to it (technically, the one definition rule says it must be defined exactly once in the program.)

Nevermind, unary plus to the rescue:

int x = std::min(0, +A::value);

The unary plus creates a temporary with the same value, and the reference binds to the temporary, so we can work around the missing definition.

This isn't something you need often, but it is a practical use of the unary plus operator.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
3

Unary + applies integral promotions. @PeteBecker's answer shows one way that can be useful.

For another, note that an unscoped enumeration type gets promoted to an integer type which can represent all values in the enum. So in C++03, even without C++11's std::underlying_type<T>, you could do:

enum MyBitMask {
    Flag1 = 0x1,
    Flag2 = 0x2,
    Flag3 = 0x4,
    Flag4 = 0x8000000
};

inline MyBitMask operator&(MyBitMask x, MyBitMask y) {
    return static_cast<MyBitMask>( +x & +y );
}

inline MyBitMask operator|(MyBitMask x, MyBitMask y) {
    return static_cast<MyBitMask>( +x | +y );
}
aschepler
  • 70,891
  • 9
  • 107
  • 161
3

Among other things, + converts lambdas to function pointers. Normally the conversion happens automatically, but sometimes it doesn't.

For example, this doesn't compile:

std::array arr{
    [](int x){return x*x;},
    [](int x){return x*x*x;},
};

You could make it work by specifying the function pointer type as the std::array template parameter, or you could just do this:

std::array arr{
    +[](int x){return x*x;},
    +[](int x){return x*x*x;},
};
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • 1
    Is there any reason to prefer the overloaded `operator+` function over `operator*` for this particular purpose? I don't see why `operator+` is considered to be the more intuitive option when a function pointer is desired. – 303 Aug 13 '21 at 17:20
  • 3
    @303 Interesting, it never occured to me that `*` also worked here. But neither of them is overloaded. `+` looks more intuitive to me because it just performs the conversion and nothing else. While `*` performs the conversion to pointer, then dereferences the pointer, and the result then gets implicitly converted back to a pointer (unless you really need a reference to function). – HolyBlackCat Aug 13 '21 at 17:28
1

A bit late, but here's a very twisted use that I stumbled across. Apparently the + operator can be useful (if perhaps not strictly necessary) when designing safeguards around the possibility of encountering empty preprocessor tokens. See this post for a more in-depth discussion.

It's practical, but by no means pleasant.

Community
  • 1
  • 1
ApproachingDarknessFish
  • 14,133
  • 7
  • 40
  • 79
0

Since for arithmetic variables operator+ generates a new value. I use it to generate value copies of reference-like (proxy) types.

template<class T> class ref_of{
   T* impl_; // or a more complicated implementation
public:
   T operator+() const{return *impl_;}
   operator T&()&{return *impl_;}
}

Another option is to use operator* but then the ref_of can be confused with a pointer-like object.

alfC
  • 14,261
  • 4
  • 67
  • 118
0

Since for arithmetic variables operator+ generates a new value, I use it in general to generate value copies of reference-like (proxy) types.

template<class T> class ref_of{
   T* impl_; // or a more complicated implementation
public:
   T operator+() const{return *impl_;} 
   operator T&()&{return *impl_;}
}
...
ref_of<T> r = t;
auto s = +r; // this forces a copy

Another option is to use operator* but then the ref_of can be confused with a pointer-like object.

alfC
  • 14,261
  • 4
  • 67
  • 118