Which are the conventional Flag operators?











up vote
-2
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 ?











share|improve this question




















  • 7




    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






  • 4




    @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






  • 1




    @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















up vote
-2
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 ?











share|improve this question




















  • 7




    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






  • 4




    @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






  • 1




    @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













up vote
-2
down vote

favorite









up vote
-2
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 ?











share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 10 at 14:00

























asked Nov 10 at 13:00









bur

17713




17713








  • 7




    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






  • 4




    @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






  • 1




    @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














  • 7




    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






  • 4




    @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






  • 1




    @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








7




7




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




4




4




@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




1




1




@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












1 Answer
1






active

oldest

votes

















up vote
2
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 as a>b


  • !(a != b) is expected to be the same as a==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...).






share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    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















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    2
    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 as a>b


    • !(a != b) is expected to be the same as a==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...).






    share|improve this answer



























      up vote
      2
      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 as a>b


      • !(a != b) is expected to be the same as a==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...).






      share|improve this answer

























        up vote
        2
        down vote



        accepted







        up vote
        2
        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 as a>b


        • !(a != b) is expected to be the same as a==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...).






        share|improve this answer














        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 as a>b


        • !(a != b) is expected to be the same as a==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...).







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 10 at 14:20

























        answered Nov 10 at 14:10









        Christophe

        38.9k43474




        38.9k43474






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            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















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            Academy of Television Arts & Sciences

            L'Équipe

            1995 France bombings