Bool Operator ++ and --

bool operator ++ and --

It comes from the history of using integer values as booleans.

If x is an int, but I am using it as a boolean as per if(x)... then incrementing will mean that whatever its truth value before the operation, it will have a truth-value of true after it (barring overflow).

However, it's impossible to predict the result of -- given knowledge only of the truth value of x, as it could result in false (if the integral value is 1) or true (if the integral value is anything else - notably this includes 0 [false] and 2 or more [true]).

So as a short-hand ++ worked, and -- didn't.

++ is allowed on bools for compatibility with this, but its use is deprecated in the standard and it was removed in C++17.


This assumes that I only use x as an boolean, meaning that overflow can't happen until I've done ++ often enough to cause an overflow on it's own. Even with char as the type used and CHAR_BITS something low like 5, that's 32 times before this doesn't work any more (that's still argument enough for it being a bad practice, I'm not defending the practice, just explaining why it works) for a 32-bit int we of course would have to use ++ 2^32 times before this is an issue. With -- though it will only result in false if I started with a value of 1 for true, or started with 0 and used ++ precisely once before.

This is different if we start with a value that is just a few below 0. Indeed, in such a case we might want ++ to result in the false value eventually such as in:

int x = -5;
while(++x)
doSomething(x);

However, this example treats x as an int everywhere except the conditional, so it's equivalent to:

int x = -5;
while(++x != 0)
doSomething(x);

Which is different to only using x as a boolean.

What's the difference between' bool operator()' and 'bool operator '?

operator()() is what I would call the "function operator". It makes the object behave like a function would, in the sense that I can use the same syntax as a function if I overload it:

class foo {
bool operator()() {
//...
}
// ...
};

// later...
bool myBool = myFoo();

As you can see, it acts like a function would.

operator<(), on the other hand, is a comparison operator. It allows me to use my foo in a comparison context, most commonly in if statements:

class foo {
bool operator<(const foo& otherFoo) const {
//...
}
// ...
};

// later...
if(myFoo1 < myFoo2) {
//...
}


Edit:

I tried replacing < with () but it threw an error

Without knowing the context you are trying to use them in, it's hard to answer why, but it's good to know that these two not only aren't the same, but are usually used in very different contexts. You can't just change the < to a () and expect it to work. C++ doesn't work that way. You need to change the context the operators are used in, not just what operator your class has overloaded.

Why ++ operator over bool is defined?? however -- is not in C++

Refer to the documentation:
https://msdn.microsoft.com/en-us/library/tf4dy80a.aspx

When a postfix or prefix ++ operator is applied to a variable of type
bool, the variable is set to true. The postfix or prefix -- operator
cannot be applied to a variable of this type.

C++: using class with explicit operator bool overloaded

The question seems to be how to both (1) have implicit conversion to bool and (2) avoid integer promotion/conversion. Delete the conversion to int:

class MyBool
{
public:
operator bool() const
{
return value_;
};

operator int() const = delete;

private:
bool value_ = false;
};

All of the lines in the question now compile because implicit conversion is allowed. And none of the safe-bool problems compile because integer conversion is deleted:

MyBool x;
int i = x;
x << 1;
x < 1;

`bool n;` `n++;` is invalid but `n=n+1;` or `n=n+3` such things works what's the significance of this?

As you can see in section 5.3.2 of standard draft N4296, this capability has been deprecated

The operand of prefix ++ is modified by adding 1, or set to true if it is bool (this use is deprecated)

Please note that the expression n=n+3; is not a unary statement, and it's not something that we could call deprecated. If we call it deprecated, the first problem is that there will be no implicit conversion from bool to int, for example. Since they don't know what you want to do with a not unary statement, it is reasonable that the below code gives you the output 2 for i(Deprecating this is not acceptable)

bool b = true;
int i = 1;
i = i + b;

In your example, what happens is implicit conversion from bool->int->bool

bool n=-1;
n++; // It's a unary statement(so based on the draft, it would not compile)
n=n+3; // This compiles (type(n+3) is now int, and then int is converted to bool)

Why unary increment is deprecated?

I use Galik's comment for completing this answer:

With ++b if you promote the bool b to int you end up with an r-value temporary. You can't increment r-values. So in order for ++b to have ever worked it must have been a bool operation, not a promotion to an arithmetic value. Now, that bool operation has been banned. But promotions remain legal so arithmetic that uses promoted values is fine.

How to overload polymorphic == and != operator in c++

You mentioned in the comments that this form of comparison is an imposed restriction (to compare among siblings of a child type). If its an imposed restriction that you need to somehow perform this with inheritance, then one option is to fulfill the base signature and use dynamic_cast. Note that this is not a clean approach, but it might be the expected solution for this problem if this is some form of assignment.

dynamic_cast uses Runtime Type Information (RTTI) to determine whether an instance to a base class is actually an instance of the derived class. When you use it with a pointer argument, it returns nullptr on failure -- which is easily testable:

auto p = dynamic_cast<const Book*>(&other);
if (p == nullptr) { // other is not a book
return false;
}
// compare books

You can use this along with a virtual function to satisfy the hierarchy. However, to avoid possible ambiguities with c++20's generated symmetric operator==/operator!= functions, it's usually better to do this through a named virtual function rather than the operator== itself in order to prevent ambiguity:

class Media {
public:
virtual ~Media() = default;

bool operator==(const Media& other) const { return do_equals(other); }

private:
virtual bool do_equals(const Media& other) const = 0;
};

class Book : public Media {
...
private:
bool do_equals(const Media& other) const override {
auto* p = dynamic_cast<const Book*>(&other);
if (p == nullptr) { return false; }

return (... some comparison logic ...);
}
...
};

... Same with Game ...

Since we never define operator==(const Book&) or operator==(const Game&), we won't see this shadow the base-class' operator==; instead it always dispatches through the base's operator==(const Media&) -- which is non-virtual and prevents ambiguity.

This would allow a Book and a Game to be comparable, but to return false -- whereas two Book or two Game objects may be compared with the appropriate logic.

Live Example



That said...

This approach is not a good design, as far as software architecture goes. It requires the derived class to query what the type is -- and usually by the time you need to do this, that's an indication that the logic is funky. And when it comes to equality operators, it also leads to complications with symmetry -- where a different derived class may choose to compare things weirdly with different types (imagine a Media that may compare true with other different media; at which point, the order matters for the function call).

A better approach in general is to define each of the respective equality operators between any types that logically require equality comparison. If you are in C++20 this is simple with symmetric equality generation; but pre-C++20 is a bit of a pain.

If a Book is meant to be comparable to a Game, then define operator==(const Game&) or operator==(const Book&, const Game&). Yes, this may mean you have a large number of operator==s to define for each of them; but its much more coherent, and can get better symmetry (especially with C++20's symmetric equality):

bool operator==(const Game&, const Book&);
bool operator==(const Book&, const Game&); // Generated in C++20
bool operator==(const Game&, const Game&);
bool operator==(const Book&, const Book&);

In an organization like this, Media may not even be logical as a 'Base class'. It may be more reasonable to consider some form of static polymorphism instead, such as using std::variant -- which is touched on in @Jarod42's answer. This would allow the types to be homogeneously stored and compared, but without requiring casting from the base to the derived type:

// no inheritance:
class Book { ... };
class Game { ... };

struct EqualityVisitor {
// Compare media of the same type
template <typename T>
bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; }

// Don't compare different media
template <typename T, typename U>
bool operator()(const T&, const U&) const { return false; }
};

class Media
{
public:
...

bool operator==(const Media& other) const {
return std::visit(EqualityVisitor{}, m_media, other.m_media);
}
private:
std::variant<Book, Game> m_media;
};

Live Example

This would be my recommended approach, provided the forms of media are meant to be fixed and not extended.

Python: justification for boolean operators (and, or) not returning booleans

In Python's case, the bool type didn't even exist until over a decade after the language was released. If it had existed from the start, perhaps and and or would have been defined differently. But, as is, backward compatibility was far more important. From the PEP that introduced the type:

Another consequence of the compatibility requirement is that the expression "True and 6" has the value 6, and similarly the expression "False or None" has the value None. The "and" and "or" operators are usefully defined to return the first argument that determines the outcome, and this won't change; in particular, they don't force the outcome to be a bool. Of course, if both arguments are bools, the outcome is always a bool. It can also easily be coerced into being a bool by writing for example "bool(x and y)".

EDIT: BTW, at its start, Python was intended to "bridge the gap" between programming in "data-rich" languages like C and "convenient" languages like Unixy shells (sh, csh, etc). Python's and and or were more like && and || act in shell languages, consuming - left to right - all and only the operands needed to resolve whether the overall chain succeeded ("true") or failed ("false").

Operator |= for a boolean in C++

On booleans, | yields the same result as ||, but doesn't short-circuit. The right operand of |= is always evaluated.



Related Topics



Leave a reply



Submit