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 ?











share|improve this question




















  • 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






  • 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















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 ?











share|improve this question




















  • 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






  • 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













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 ?











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

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 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




    @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




    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




    @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












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 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',
    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
































    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 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
      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 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
        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 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.1k43473




        38.1k43473






























             

            draft saved


            draft discarded



















































             


            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




















































































            Popular posts from this blog

            Full-time equivalent

            Bicuculline

            さくらももこ