0

In C I am able to take two or more enumerated flags and inclusive OR them: (flag1 | flag2)

In C++ I cannot do the same thing. I have some flags that I've scoped to my class but to OR them I have to cast. It looks like this:

namespace name
{
    class test
    {
    public:
        enum flag
        {
            firstflag = 1, secondflag = 2, thirdflag = 4
        };

        void foo(flag flags)
        {
            return;
        }
    };
}

int main(int argc, char *argv[])
{
    name::test obj;

    obj.foo((name::test::flag)(name::test::firstflag | name::test::secondflag));

    return 0;
}

That's kind of a mouthful, more in the real code than this example. I am wondering if there is a better way. I could change the argument passed to int void foo(int flags) but then in the Visual Studio 2010 debugger I wouldn't see the flags ORed, just a number.


Without the cast I get an error:

obj.foo(name::test::firstflag | name::test::secondflag);
error C2664: 'name::test::foo' : cannot convert parameter 1 from 'int' to 'name::test::flag'

I searched on stackoverflow and found a question with the answer to overload the | operator:
c++ - "enum - invalid conversion from int" in class - Stack Overflow

Yet when I use std::ios flags I don't have to do any casting, why is that? For example fstream has a prototype like for example fstream(char *filename, std::ios_base) and I can do this in my code:

fstream("filename",  ios::in | ios::out);


What do you guys suggest? I do not have a lot of C++11 capabilities so if you could keep that in mind when answering. Thanks

2
  • 1
    Looking at std::ios_base, the flags are declared static constexpr type variable = implementation Commented Mar 7, 2014 at 0:26
  • Aside from your question, the mouthful is easily slightly shortened: coliru.stacked-crooked.com/a/f9898f77f95c3c8b Commented Mar 7, 2014 at 0:48

3 Answers 3

5

In the GCC implementation of ios::in, ios::out, etc. They use operator overloading to get the desired effect. E.g.

inline _GLIBCXX_CONSTEXPR _Ios_Openmode
operator|(_Ios_Openmode __a, _Ios_Openmode __b)
{ return _Ios_Openmode(static_cast<int>(__a) | static_cast<int>(__b)); }

In your case you could define the following method:

inline flag operator|(flag f1, flag f2)
{ 
  return flag(static_cast<int>(f1) | static_cast<int>(f2)); 
}

Cheers,

Sign up to request clarification or add additional context in comments.

2 Comments

This actually answers the question! +1
Does static_cast really make a difference here? I'm surprised to see that because in visual studio they use (int)
1

std::bitset is pretty good style for C++. Reference

#include <bitset>

namespace Flags {
enum Flags {
  first, second, third, NUM_FLAGS
};
}

class Test {
public:
  void foo(std::bitset<Flags::NUM_FLAGS> flags) {
    return;
  }
};

int main() {
  std::bitset<Flags::NUM_FLAGS> flags;
  flags[Flags::first] = true;
  flags[Flags::second] = false;
  flags[Flags::third] = true;

  Test obj;
  obj.foo(flags);
}

Comments

0

You can write a template class to convert flags to std::bitset<> (which doesn't need ) indices and vice versa:

template<typename BitFieldType, BitFieldType BitValue, int8_t CurIndex>
struct BitIndexSelector;

template<typename BitFieldType, BitFieldType BitValue, int8_t CurIndex>
struct BitIndexSelector
{
    static const int8_t ResultIndex =
            ((CurIndex != -1) &&
             (((((BitFieldType)1) << CurIndex) & BitValue) > 0)
            ? CurIndex
            : BitIndexSelector
                <BitFieldType
                ,BitValue
                ,CurIndex - 1>::ResultIndex);

};

template<typename BitFieldType, BitFieldType BitValue>
struct BitIndexSelector<BitFieldType,BitValue,-1>
{
    static const int8_t ResultIndex = -1;
};

template<typename BitFieldType, BitFieldType BitValue = 0>
struct GetBitIndex
{
    static const int8_t Index =
        BitIndexSelector
            < BitFieldType
            , BitValue
            , sizeof(BitFieldType) * sizeof(char) * CHAR_BIT>::ResultIndex;
    typedef std::bitset<sizeof(BitFieldType) * CHAR_BIT> BitsetType;
};

Here's a sample for usage to convert the bitmask defined poll() event types to index values for accessing the various flags represented with a std::bitset<> in a convenient way:

enum PollEvents
{
    EV_POLLIN = GetBitIndex<short,POLLIN>::Index ,
    EV_POLLOUT = GetBitIndex<short,POLLOUT>::Index ,
    EV_POLLPRI = GetBitIndex<short,POLLPRI>::Index ,
    EV_POLLRDHUP = GetBitIndex<short,POLLRDHUP>::Index ,
    EV_POLLERR = GetBitIndex<short,POLLERR>::Index ,
    EV_POLLHUP = GetBitIndex<short,POLLHUP>::Index ,
};

A corresponding std::bitset<> can be manipulated using the indices defined in the enum above:

GetBitIndex<short>::BitsetType pollEventMask;

pollEvents[EV_POLLIN] = true; // set the POLLIN flag
pollEvents[EV_POLLERR] = false; // unset the POLLERR flag

The two operations above will do the same as:

short pollEventMask= POLLHUP | POLLERR; // Initialization just to show preset 
                                        // values
pollEventMask = (pollEventMask | POLLIN) & ~POLLERR; // This is the equivalent
                                                     // for the operations shown
                                                     // above

Some people claim for shortness, I personally claim for easy to read and use code on the semantics level (as long it doesn't hurt performance or footprint significantly).

A complete code sample can be found here (note it's only a gist I made, to bring it into productive state in another project).

4 Comments

That appears to be complete overkill
@MooingDuck I have found that pretty useful for some contexts. I'm pretty sure that using a std::bitset<> to manage a certain set of flags is in no way more inefficient, than manipulating these directly with the |, & and ~ operators.
There is the fact that it's built in and everyone ought to know about it. To justify a custom version, you'd have to demonstrate that yours is significantly better in some way. I an't even figure out what yours does much less why it's better.
@MooingDuck I edited to clarify a bit (ha pun intended ;) ). If one doesn't need such translation, just to define the bitset indices as enum is the more reasonable solution of course (as shown in Sam Cristall's answer).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.