Pergunta

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?

Foi útil?

Solução

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.

Outras dicas

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.

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.

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.

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

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.

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

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.

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top