Can't reset QFlag in simple class
-
Hi,
I'm trying implement QFlags. I wrote enum in MyClass but in this class I can only set this flag only once. After that I can't see any changes in Debugger in variable
MyFlags flag;
. Why? Here is the code:#include <QFlags> class MyClass { public: enum MyFlag { Yes, // default No }; Q_DECLARE_FLAGS(MyFlags, MyFlag) MyClass(){ flag.setFlag(Yes); // Yes(0) flag.setFlag(No); // No(1) flag.setFlag(Yes); // No(1) flag.setFlag(No); // No(1) flag.setFlag(Yes); // No(1) } private: MyFlags flag; };
-
Hi
I think its due to using a value of zero for one of the enums.try with
enum MyFlag { Yes = 1, // default No =2 };
then it looks as expected
-
Did you actually check the current value after setting it? Otherwise I don't see how you would really know that it does not work.
-
Hi
Its store OR combination of the enums. (in your case zero and 1 )
The code isQ_DECL_RELAXED_CONSTEXPR inline QFlags &setFlag(Enum flag, bool on = true) noexcept { return on ? (*this |= flag) : (*this &= ~Int(flag)); }
becomes
value =0
value |= 0
value |= 1
value |= 0
...So it seems you are expecting it to behave differently?
-
@Christian-Ehrlicher yes, I set a breakpoint and line by line watch the status of variable
flag
. And in other my application the behavior is the same and I can see this not only with debugger but also how the application runs.@mrjj thank you for explanation but this code exceeds my knowledge on C/C++ operators :)
I wanted that QFlag would be a trigger wich has two positions:Yes
andNo
. I could replace it withbool
variable but I want to get experience with QFlags (or C++ flags).
So inside my class I need to be able to change the satus offlag
manually. I thought if I writeflag.setFlag(Yes);
thenflag.testFlag(Yes);
should returntrue
and in opposite:flag.setFlag(No);
flag.testFlag(No);
should returntrue
But this doesn't work like I expected... -
@Please_Help_me_D
Hi
yes a bool would act as a toggle but QFlags is
actually more like a list of bools.
You can then set one or more of these bools.so say you had something to describe a person
enum MyFlag { Clever, // default Handsome, Rich };
then
flag.setFlag( Clever );
flag.setFlag( Handsome );Then you set the flags for the person to be Clever and handsome.
For your exmaple to make it flip/flop you would have to do
flag.setFlag(Yes ,true ); // turn on
flag.setFlag(Yes, false); // turn off
flag.setFlag(No); // turn ONSetting No alone , will not turn off Yes.
It means that No is on also. (or off)Hope this makes better sense then :)
-
@mrjj thank, now I understood but the problem is in this way they also don't work.
I just tried to rewrite MyClass here it is:#include <QFlags> class MyClass { public: enum MyFlag { Yes, // default No }; Q_DECLARE_FLAGS(MyFlags, MyFlag) MyClass(){ flag.setFlag(Yes, true); bool a = flag.testFlag(Yes); // a == true flag.setFlag(Yes, false); bool b = flag.testFlag(Yes); // b == true flag.setFlag(Yes, true); bool c = flag.testFlag(Yes); // c == true } private: MyFlags flag; };
Why all the three bool vars are true? Is that ok?
-
Hi
I think its due to using a value of zero for one of the enums.try with
enum MyFlag { Yes = 1, // default No =2 };
then it looks as expected
-
Hi,
It is shown in and explained in the QFlags that each item of your flags need to have a different value (1 -> 2 -> 4 -> 8 -> etc.) that can be ORed otherwise you cannot establish which was set. You can do that using a binary format for your number, it will make things clearer.
-
@SGaist thank you!
But it is always difficult for me to read documentation about something new that I don't have any idea. It becomes much easier when I already have some representation about studied topic.
As example I've read both this and that but nothing helped me to solve my task. I'm like a slowpoke :)
But now when I know that QFlag is something like a list of boolean variables I can match documentation with my needs. I always search "how to solve my problem" in Internet and only then I disturb people from communities.
This is just my excuses so you would not think that I don't do anything to solve my problem by myself :)I really appreciate forum's people help because you save a lot of time and nerves and honestly saying I would have never learned programming (Matlab and C/C++) if there were not such communities.
-
Hi
Yes its like a list
but to make it take up far less space, it uses bits instead of a bool.
So basically QFlags helps you get/and set the bits.You know for programming a value can also be shown as binary 0 and 1 ?
When you OR something, then just one of the bit has to be set then it becomes set in the result too.
0 1 0 1 OR 0 1 1 0 ------- 0 1 1 1
with AND operator both bits must be set to be set in the result.
Thats how QFlags works interinally
if we look at
Q_DECL_RELAXED_CONSTEXPR inline QFlags &setFlag(Enum flag, bool on = true) noexcept { return on ? (*this |= flag) : (*this &= ~Int(flag)); }
then it says
if (on is true )
value = value OR flag ( in your case yes )
else if on is false ( to turn off )
value = value AND (negative) flagthe last part is taking out the bits that belong to the value for the flag.
So AND / OR is not that difficult to understand at a high level as it simply
manipulate the values as bits. -
@mrjj thank you!
I understood something but some interesting things I don't. Here what I get.
Yes I understand byte/bitThis:
on ? (*this |= flag) : (*this &= ~Int(flag));
is equal to:
if ( on == true ){ *this = (*this || flag); } else { *this = (*this &~ Int(flag)); }
right?
If so then to understand the mathematics I need to understand what in bit representation is:*this
,flag
,Int(flag)
In my caseflag
is equal to 1 right ( enum MyFlag { Yes = 1} )? in bit representation 0001
But what is in*this
before assigning anything (operator =) and what functionInt()
does? simply convertsflag
to integer? as I know this type of casting doesn't change bits of the number it simply tells "these bits should be read as int"
Something like that:)||________________
By the way how to turn on notifications when somebody answers me or writes in topic created by me? -
Yes odd syntax is called Conditional ternary operator:
but is just a one liner if else.(condition) ? (if_true) : (if_false)
The *this de reference the this pointer.
so its what it points to.
This is done to trigger the operator = which QFlags have overloaded.
so its a way to assign the value to it self using =the Int() is a type cast like (Int)flag;
But its a bit more if we look at source#if defined(Q_CC_MSVC) || defined(Q_CLANG_QDOC) // see above for MSVC // the definition below is too complex for qdoc typedef int Int; #else typedef typename std::conditional< std::is_unsigned<typename std::underlying_type<Enum>::type>::value, unsigned int, signed int >::type Int; #endif
so when not MSVC compiler it also checks the type
And if you think that looks strange, you are right :)
Its c++ templates and while really useful, its also
often ugly and unreadable. So ignore it until later in your training. -
@mrjj all the things that depend on the compiler features are far outside of my current possibilities :)
So I think I begin to understand the magic behind QFlag.
returned value is of typebool
andbool
is not a single bit but rather a byte (maybe few bytes). So any numbers written inYes
except zero in this expression:*this || flag
returnes some byte (bytes) where even a single (or more) bits is not zero. A
bool
which has even a single (or more) non zero bit should returntrue
right?
And I believe that behind this dark veil:*this &~ Int(flag)
are hidden all zeroed bits :)
By the way is it necessary to assign numbers to enum definitions (Yes, No etc) that are equal the power of 2 (1, 2, 4, 8, 16 ...)? as in many examples
-
Ok that's good :)
maybe you are ready for
https://www.youtube.com/watch?v=TKEaakjKrMc
Bitwise AND / ORActually the dark veil:
is using AND and BINARY NOT
to remove the bits for a flagYes, you must use power of 2 values as else some of the values will have
overlapping bit representation and things get funny when you combine certain flags.