Which are the conventional Flag operators?
up vote
-3
down vote
favorite
I have defined an enum that I want to use for storing flags in variables. The intent is to be able to set several flags, and being able to check which ones are set.
For this purpose, I need two operations: one to find out if a
is in b
, and a second one to find out if a
is not in b
. I implemented them using operator overloads. I picked <=
and !=
arbitrarily:
enum Flag { NoFlags, B, C, D=4 };
inline Flag operator |(Flag a, Flag b) {
return static_cast<Flag >(static_cast<int>(a) | static_cast<int>(b)); }
inline bool operator <=(Flag a, Flag b) { return a == (a & b); }
inline bool operator !=(Flag a, Flag b) { return !(a<=b); }
This works fine. So for example:
Flag flags1 = A|C;
Flag flags2 = B|D;
Flag flags3 = NoFlags|A|B|C|D;
A <= flags1 //true
A != flags2 //true
C != flags3 //false
B <= flags1 //false
I picked <=
and !=
arbitrarily. I know they normally have completely different meanings. So I wonder:
is there a commonly accepted practice of using other operators for representing these two operations ?
Or would it be better to use functions instead of operator overloads ?
c++ enums operator-overloading flags
|
show 1 more comment
up vote
-3
down vote
favorite
I have defined an enum that I want to use for storing flags in variables. The intent is to be able to set several flags, and being able to check which ones are set.
For this purpose, I need two operations: one to find out if a
is in b
, and a second one to find out if a
is not in b
. I implemented them using operator overloads. I picked <=
and !=
arbitrarily:
enum Flag { NoFlags, B, C, D=4 };
inline Flag operator |(Flag a, Flag b) {
return static_cast<Flag >(static_cast<int>(a) | static_cast<int>(b)); }
inline bool operator <=(Flag a, Flag b) { return a == (a & b); }
inline bool operator !=(Flag a, Flag b) { return !(a<=b); }
This works fine. So for example:
Flag flags1 = A|C;
Flag flags2 = B|D;
Flag flags3 = NoFlags|A|B|C|D;
A <= flags1 //true
A != flags2 //true
C != flags3 //false
B <= flags1 //false
I picked <=
and !=
arbitrarily. I know they normally have completely different meanings. So I wonder:
is there a commonly accepted practice of using other operators for representing these two operations ?
Or would it be better to use functions instead of operator overloads ?
c++ enums operator-overloading flags
6
Making up your own meanings for operators with absolutely no similarity to existing meanings is usually discouraged, as a violation of the Principle of Least Astonishment. (Some even say the iostreamsoperator<<
andoperator>>
were a mistake, though at this point they're well-established and generally understood.) I would go with named functions.
– aschepler
Nov 10 at 13:03
3
@MatthieuBrucher Enum types are guaranteed to be able to store values up to the nearest power of two minus one after the largest enumerator value, so it's in fact safe to cast bitwise-or combinations of enumerator values to the enum type.
– aschepler
Nov 10 at 13:06
@aschepler this is in fact a good answer to a perfectly valid question. Just post it as such and I'll update
– Christophe
Nov 10 at 13:46
Yes, thank you, that's all I really needed to know. If posted as an answer, I'll accept.
– bur
Nov 10 at 13:56
@bur There were some downvotes and close votes probably because some people didn't get what you meant with the flags and the operators. I have edited slightly to make it clearer. Don't hesitate to correct if I was mistaken.
– Christophe
Nov 10 at 13:59
|
show 1 more comment
up vote
-3
down vote
favorite
up vote
-3
down vote
favorite
I have defined an enum that I want to use for storing flags in variables. The intent is to be able to set several flags, and being able to check which ones are set.
For this purpose, I need two operations: one to find out if a
is in b
, and a second one to find out if a
is not in b
. I implemented them using operator overloads. I picked <=
and !=
arbitrarily:
enum Flag { NoFlags, B, C, D=4 };
inline Flag operator |(Flag a, Flag b) {
return static_cast<Flag >(static_cast<int>(a) | static_cast<int>(b)); }
inline bool operator <=(Flag a, Flag b) { return a == (a & b); }
inline bool operator !=(Flag a, Flag b) { return !(a<=b); }
This works fine. So for example:
Flag flags1 = A|C;
Flag flags2 = B|D;
Flag flags3 = NoFlags|A|B|C|D;
A <= flags1 //true
A != flags2 //true
C != flags3 //false
B <= flags1 //false
I picked <=
and !=
arbitrarily. I know they normally have completely different meanings. So I wonder:
is there a commonly accepted practice of using other operators for representing these two operations ?
Or would it be better to use functions instead of operator overloads ?
c++ enums operator-overloading flags
I have defined an enum that I want to use for storing flags in variables. The intent is to be able to set several flags, and being able to check which ones are set.
For this purpose, I need two operations: one to find out if a
is in b
, and a second one to find out if a
is not in b
. I implemented them using operator overloads. I picked <=
and !=
arbitrarily:
enum Flag { NoFlags, B, C, D=4 };
inline Flag operator |(Flag a, Flag b) {
return static_cast<Flag >(static_cast<int>(a) | static_cast<int>(b)); }
inline bool operator <=(Flag a, Flag b) { return a == (a & b); }
inline bool operator !=(Flag a, Flag b) { return !(a<=b); }
This works fine. So for example:
Flag flags1 = A|C;
Flag flags2 = B|D;
Flag flags3 = NoFlags|A|B|C|D;
A <= flags1 //true
A != flags2 //true
C != flags3 //false
B <= flags1 //false
I picked <=
and !=
arbitrarily. I know they normally have completely different meanings. So I wonder:
is there a commonly accepted practice of using other operators for representing these two operations ?
Or would it be better to use functions instead of operator overloads ?
c++ enums operator-overloading flags
c++ enums operator-overloading flags
edited Nov 10 at 14:00
asked Nov 10 at 13:00
bur
13313
13313
6
Making up your own meanings for operators with absolutely no similarity to existing meanings is usually discouraged, as a violation of the Principle of Least Astonishment. (Some even say the iostreamsoperator<<
andoperator>>
were a mistake, though at this point they're well-established and generally understood.) I would go with named functions.
– aschepler
Nov 10 at 13:03
3
@MatthieuBrucher Enum types are guaranteed to be able to store values up to the nearest power of two minus one after the largest enumerator value, so it's in fact safe to cast bitwise-or combinations of enumerator values to the enum type.
– aschepler
Nov 10 at 13:06
@aschepler this is in fact a good answer to a perfectly valid question. Just post it as such and I'll update
– Christophe
Nov 10 at 13:46
Yes, thank you, that's all I really needed to know. If posted as an answer, I'll accept.
– bur
Nov 10 at 13:56
@bur There were some downvotes and close votes probably because some people didn't get what you meant with the flags and the operators. I have edited slightly to make it clearer. Don't hesitate to correct if I was mistaken.
– Christophe
Nov 10 at 13:59
|
show 1 more comment
6
Making up your own meanings for operators with absolutely no similarity to existing meanings is usually discouraged, as a violation of the Principle of Least Astonishment. (Some even say the iostreamsoperator<<
andoperator>>
were a mistake, though at this point they're well-established and generally understood.) I would go with named functions.
– aschepler
Nov 10 at 13:03
3
@MatthieuBrucher Enum types are guaranteed to be able to store values up to the nearest power of two minus one after the largest enumerator value, so it's in fact safe to cast bitwise-or combinations of enumerator values to the enum type.
– aschepler
Nov 10 at 13:06
@aschepler this is in fact a good answer to a perfectly valid question. Just post it as such and I'll update
– Christophe
Nov 10 at 13:46
Yes, thank you, that's all I really needed to know. If posted as an answer, I'll accept.
– bur
Nov 10 at 13:56
@bur There were some downvotes and close votes probably because some people didn't get what you meant with the flags and the operators. I have edited slightly to make it clearer. Don't hesitate to correct if I was mistaken.
– Christophe
Nov 10 at 13:59
6
6
Making up your own meanings for operators with absolutely no similarity to existing meanings is usually discouraged, as a violation of the Principle of Least Astonishment. (Some even say the iostreams
operator<<
and operator>>
were a mistake, though at this point they're well-established and generally understood.) I would go with named functions.– aschepler
Nov 10 at 13:03
Making up your own meanings for operators with absolutely no similarity to existing meanings is usually discouraged, as a violation of the Principle of Least Astonishment. (Some even say the iostreams
operator<<
and operator>>
were a mistake, though at this point they're well-established and generally understood.) I would go with named functions.– aschepler
Nov 10 at 13:03
3
3
@MatthieuBrucher Enum types are guaranteed to be able to store values up to the nearest power of two minus one after the largest enumerator value, so it's in fact safe to cast bitwise-or combinations of enumerator values to the enum type.
– aschepler
Nov 10 at 13:06
@MatthieuBrucher Enum types are guaranteed to be able to store values up to the nearest power of two minus one after the largest enumerator value, so it's in fact safe to cast bitwise-or combinations of enumerator values to the enum type.
– aschepler
Nov 10 at 13:06
@aschepler this is in fact a good answer to a perfectly valid question. Just post it as such and I'll update
– Christophe
Nov 10 at 13:46
@aschepler this is in fact a good answer to a perfectly valid question. Just post it as such and I'll update
– Christophe
Nov 10 at 13:46
Yes, thank you, that's all I really needed to know. If posted as an answer, I'll accept.
– bur
Nov 10 at 13:56
Yes, thank you, that's all I really needed to know. If posted as an answer, I'll accept.
– bur
Nov 10 at 13:56
@bur There were some downvotes and close votes probably because some people didn't get what you meant with the flags and the operators. I have edited slightly to make it clearer. Don't hesitate to correct if I was mistaken.
– Christophe
Nov 10 at 13:59
@bur There were some downvotes and close votes probably because some people didn't get what you meant with the flags and the operators. I have edited slightly to make it clearer. Don't hesitate to correct if I was mistaken.
– Christophe
Nov 10 at 13:59
|
show 1 more comment
1 Answer
1
active
oldest
votes
up vote
1
down vote
accepted
Most readers of your code (and maybe even your future self) will get very confused, because the meaning you give to the operators is not consistent with the standard operators. For example:
!(a <= b)
is expected to be the same asa>b
!(a != b)
is expected to be the same asa==b
flags1 != flags3
would no longer mean that exactly the same flags are set in both variables
For this reason, and according to the principle of least astonishment, I'd strongly advise against your choice.
The common practice with operators on flags is to use |
to set flags and &
in combination with ~
to reset flags, and &
to test flags. But this is done, assuming predictable bitwise operations, and not a higher level interface as yours.
In your case, I'd recommend using functions instead of operators, and let the function names clearly express your intent (e.g. is_included()
). I'd even suggest to consider enum classes with member functions for a better encapsulation.
Since you seem to consider your Flag
variables as a set of combined individual flags, you could get inspired by the std::set
interface if you're looking for a consistent and known naming scheme (e.g. insert()
, find()
, contains()
, merge()
, etc...).
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
Most readers of your code (and maybe even your future self) will get very confused, because the meaning you give to the operators is not consistent with the standard operators. For example:
!(a <= b)
is expected to be the same asa>b
!(a != b)
is expected to be the same asa==b
flags1 != flags3
would no longer mean that exactly the same flags are set in both variables
For this reason, and according to the principle of least astonishment, I'd strongly advise against your choice.
The common practice with operators on flags is to use |
to set flags and &
in combination with ~
to reset flags, and &
to test flags. But this is done, assuming predictable bitwise operations, and not a higher level interface as yours.
In your case, I'd recommend using functions instead of operators, and let the function names clearly express your intent (e.g. is_included()
). I'd even suggest to consider enum classes with member functions for a better encapsulation.
Since you seem to consider your Flag
variables as a set of combined individual flags, you could get inspired by the std::set
interface if you're looking for a consistent and known naming scheme (e.g. insert()
, find()
, contains()
, merge()
, etc...).
add a comment |
up vote
1
down vote
accepted
Most readers of your code (and maybe even your future self) will get very confused, because the meaning you give to the operators is not consistent with the standard operators. For example:
!(a <= b)
is expected to be the same asa>b
!(a != b)
is expected to be the same asa==b
flags1 != flags3
would no longer mean that exactly the same flags are set in both variables
For this reason, and according to the principle of least astonishment, I'd strongly advise against your choice.
The common practice with operators on flags is to use |
to set flags and &
in combination with ~
to reset flags, and &
to test flags. But this is done, assuming predictable bitwise operations, and not a higher level interface as yours.
In your case, I'd recommend using functions instead of operators, and let the function names clearly express your intent (e.g. is_included()
). I'd even suggest to consider enum classes with member functions for a better encapsulation.
Since you seem to consider your Flag
variables as a set of combined individual flags, you could get inspired by the std::set
interface if you're looking for a consistent and known naming scheme (e.g. insert()
, find()
, contains()
, merge()
, etc...).
add a comment |
up vote
1
down vote
accepted
up vote
1
down vote
accepted
Most readers of your code (and maybe even your future self) will get very confused, because the meaning you give to the operators is not consistent with the standard operators. For example:
!(a <= b)
is expected to be the same asa>b
!(a != b)
is expected to be the same asa==b
flags1 != flags3
would no longer mean that exactly the same flags are set in both variables
For this reason, and according to the principle of least astonishment, I'd strongly advise against your choice.
The common practice with operators on flags is to use |
to set flags and &
in combination with ~
to reset flags, and &
to test flags. But this is done, assuming predictable bitwise operations, and not a higher level interface as yours.
In your case, I'd recommend using functions instead of operators, and let the function names clearly express your intent (e.g. is_included()
). I'd even suggest to consider enum classes with member functions for a better encapsulation.
Since you seem to consider your Flag
variables as a set of combined individual flags, you could get inspired by the std::set
interface if you're looking for a consistent and known naming scheme (e.g. insert()
, find()
, contains()
, merge()
, etc...).
Most readers of your code (and maybe even your future self) will get very confused, because the meaning you give to the operators is not consistent with the standard operators. For example:
!(a <= b)
is expected to be the same asa>b
!(a != b)
is expected to be the same asa==b
flags1 != flags3
would no longer mean that exactly the same flags are set in both variables
For this reason, and according to the principle of least astonishment, I'd strongly advise against your choice.
The common practice with operators on flags is to use |
to set flags and &
in combination with ~
to reset flags, and &
to test flags. But this is done, assuming predictable bitwise operations, and not a higher level interface as yours.
In your case, I'd recommend using functions instead of operators, and let the function names clearly express your intent (e.g. is_included()
). I'd even suggest to consider enum classes with member functions for a better encapsulation.
Since you seem to consider your Flag
variables as a set of combined individual flags, you could get inspired by the std::set
interface if you're looking for a consistent and known naming scheme (e.g. insert()
, find()
, contains()
, merge()
, etc...).
edited Nov 10 at 14:20
answered Nov 10 at 14:10
Christophe
38.1k43473
38.1k43473
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53239201%2fwhich-are-the-conventional-flag-operators%23new-answer', 'question_page');
}
);
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
6
Making up your own meanings for operators with absolutely no similarity to existing meanings is usually discouraged, as a violation of the Principle of Least Astonishment. (Some even say the iostreams
operator<<
andoperator>>
were a mistake, though at this point they're well-established and generally understood.) I would go with named functions.– aschepler
Nov 10 at 13:03
3
@MatthieuBrucher Enum types are guaranteed to be able to store values up to the nearest power of two minus one after the largest enumerator value, so it's in fact safe to cast bitwise-or combinations of enumerator values to the enum type.
– aschepler
Nov 10 at 13:06
@aschepler this is in fact a good answer to a perfectly valid question. Just post it as such and I'll update
– Christophe
Nov 10 at 13:46
Yes, thank you, that's all I really needed to know. If posted as an answer, I'll accept.
– bur
Nov 10 at 13:56
@bur There were some downvotes and close votes probably because some people didn't get what you meant with the flags and the operators. I have edited slightly to make it clearer. Don't hesitate to correct if I was mistaken.
– Christophe
Nov 10 at 13:59