C++ Operator Overloading: Bitwise Operators & If-Check

Started by
15 comments, last by AzureBlaze 8 years, 8 months ago

Thanks for all of your answers.

@AzureBlaze

1. Wouldn't that be quite heavy for performance? Since every single of those instances has it's own list, and is used only shortly anyway..

2. Works, thanks!

@BitMaster

This would do everything I want; If it hadn't a fixed size. I wanted to create such a class exactly because of that: To avoid fixing myself on a fixed size (I mean, I probably won't use more than 4-5 flags anyway at once, so I could just use a 8bit integer, but I like to keep myself free of any restrictions...). Also I don't use boost so I won't be able to use boost::dynamic_bitset. I'll look at it for inspirations though, thanks!

@SeanMiddleditch

In this specific case I can't really allow myself to use enums, since the "flags" that are set are not really what you would expect from flags, but rather IDs generated on-the-fly; I just want to use flags because I really like the syntax (And how easy it is)

Your class looks quite complex, I'll try to understand it later :)

@Servant of the Lord

Exactly :). Although, now that I think of it, if one of the two flag-sets is empty, the intersection between the two should still return the non-empty flag-set... Which kind of defies the logic behind it. I'll explain what I actually want to do and why I want to use flagset further down this post.

@Krohm Heh, exactly, in reality using flags is probably a really bad idea. I just loved the simplicity that comes with using them, I guess. Here is what I really want to do:

In my EventHandler class, I'm able to trigger an event x, and I can hook some callback method to all events of type y. (Standard event-handler functionality I guess)

Since I want to also create some kind of scripting system later on, in order to define the entities of my game, which are all event-driven: Meaning their whole behaviour consists of callbacks being called from the eventhandler. But of course, I don't really want to let the callbacks be called by all events of type y; Let's take a collision-event as example: If I hook my entity-collision-callback to the collision event, it will be called everytime any collision happens in my game. So I need to apply some constraints, in order to have that event only called when the collision happens with this specific entity and another one.

I thought about applying these constraints with these flags:

When triggering the event, I specify the IDs of both objects colliding. Now, every callback that either has no constraints, or one of those specific constraints, will get called. Here a little pseudo-code, because I'm really bad at explaining stuff (I'll also use my UFlag class, even if it is probably the bad way of doing this.):


#define EIUF ...  //Empty Integer UFlag

//When hooking into the event. Inside my entity-class
eventHandler->hookInto(EventType::Collision, myCollisionCallback, UFlag<int>(this->ID());

//When triggering the event:

eventHandler->triggerEvent(EventType::Collision, someArgument, UFlag<int>(collision.firstObject.ID(), collision.secondObject.ID()));

//If my entity has the same ID as one of the two in the collision event, it's callback will be called.

//If a callback is specified without constraints, it will get called, regardless of the IDs.


Depending on the event, the integer-flags could mean something else.

I hope I could make myself clear unsure.png ...

Does anyone have an idea what I should use instead of those flags? As I already said, the thing is, I reaaally liked the syntax and everything.

Kind regards

Advertisement


I suspect it was supposed to be (f & uf) != 0, since the other version is definitely not equivalent. It prevents the implicit cast from unsigned to bool and all the potential compiler warnings that come with it (in VS it's usually something about runtime performance).

I do not know what his intention was, however typically if you're testing flags and you want to ensure that all of the flags you are testing are set, you want (flags & flagsToTestFor) == something, as otherwise only having some of the flags in flagsToTestFor set can still return non-zero.

So then, is the recommended method:


if((flags & flagsToTestFor) == flagsToTestFor) //The flag entirely exists (all the matching bits are 1).
if((flags & flagsToTestFor) != flagsToTestFor) //The flag doesn't entirely exist (not every matching bits is 1).

?

@Servant of the Lord

Not really, I think. I did it like that:

if (!flagsToTestFor || flagsToTestFor & flags)

Given that the "&" operator returns the non-empty flag-set if one of the two is empty (See the ideone-code in the first post).

(Also, not all flags must match: If one flag matches, it is enough to be "true" since the boolean-operator-override-thingy returns the size of the internal list: So it is only false if it is empty.)

But honestly, right now I think that I really shouldn't use flags anyway, but I can't imagine another way which is as easy...

Edit: oh whoops, I didn't notice that you weren't responding to me, sorry

@BitMaster
This would do everything I want; If it hadn't a fixed size. I wanted to create such a class exactly because of that: To avoid fixing myself on a fixed size (I mean, I probably won't use more than 4-5 flags anyway at once, so I could just use a 8bit integer, but I like to keep myself free of any restrictions...). Also I don't use boost so I won't be able to use boost::dynamic_bitset. I'll look at it for inspirations though, thanks!


I'm not sure I understand. A single number in a typedef (or using declaration) needs to be changed whenever you need more bits, everything else happens automatically thanks to template magic. That is in practically all cases a compile-time decision.

In the extreme case that you don't know about your flags until runtime (which you did not really say and is not really obvious from your examples), then yes, it won't work.

@BitMaster

Technically, I could be able to know how many bits are needed in compile-time; But since I want to implement a scripting system later on, in which those flags will be used too, I don't want to restrict the number of bits needed. Also, right now I think that bit-flags are the wrong approach to my problem anyway (See my posts above). Thanks for your help though, it is greatly appreciated!

Kind regards,

Flyverse

Solved my problem, but it was awesome to learn a bit about bits and flags. Thank you guys!

1. Wouldn't that be quite heavy for performance? Since every single of those instances has it's own list, and is used only shortly anyway..

If you do care about performance, you should revert to normal flags. Your linear search through the deque will already be too slow if you check a billion time through a billion flags.

But I guess this is not the case you're going to use it with. For these non performance critical part you should always choose the easier way. Easier to code, understand, maintain, less chance of misusing. Those 2 microseconds you saved from the user's CPU which you're not paying for is not worth a week of debugging hell.

Your method have severe flaw in it: people don't expect normal operators other than assignments or ++/-- to modify their operand. If you write y = x+5, you'll expect only y will change, not x and certainly not 5.

If you write


UFlag foo = getFlags();
if(foo & 1){
//...
}

if(foo & 2){
//...
}

you are going to run into trouble because the content of foo have changed in the first if statement. You'll have to state clearly in your documents that UFlag can't be used like this and hope people (and yourself) will remember.

Although if you have access to c++11 you can avoid some of the performance penalty by using rvalue reference


//this operator is called when the left hand side is an rvalue, which is some temp value that is going to be thrown away.
//google rvalue for more details.
UFlag &&operator&(const UFlag &rhs) && { 
	//we are not going to use "this" later, so we are free to mess with it to improve performance.
	this->list.blah(...);
	//return as an rvalue
	return move(*this);
}

This topic is closed to new replies.

Advertisement