繁体   English   中英

C ++轻松将枚举用于标志和按位运算

[英]C++ Using enumeration for flags and bitwise operations, easily

在CI中,可以采用两个或多个枚举标志并将它们包括在内(或):( (flag1 | flag2)

在C ++中,我不能做同样的事情。 我已经将某些标志作用域限定在我的班级上,但是必须将它们强制转换为OR。 看起来像这样:

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

在实际代码中,这比本示例要花很多时间。 我想知道是否有更好的方法。 我可以更改传递给int void foo(int flags)但是在Visual Studio 2010调试器中,我看不到ORed标志,只是一个数字。


没有强制转换,我会得到一个错误:

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

我在stackoverflow上进行搜索,发现了一个问题,给出了答案,以使| 运营商:
c ++-类中的“枚举-从int进行无效转换”-代码日志

但是,当我使用std::ios标志时,我不必进行任何强制转换,这是为什么呢? 例如,fstream有一个原型,例如fstream(char *filename, std::ios_base) ,我可以在我的代码中执行此操作:

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


你们有什么建议? 我没有很多C ++ 11功能,因此如果您在回答时可以牢记这一点。 谢谢

在ios :: in,ios :: out等的GCC实现中。它们使用运算符重载来获得所需的效果。 例如

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

您可以定义以下方法:

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

干杯,

std::bitset对于C ++来说是非常好的样式。 参考

#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);
}

您可以编写一个模板类以将标志转换为std::bitset<> (不需要 )索引,反之亦然:

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

这是一个示例,用于将位掩码定义的poll()事件类型转换为索引值,以便以方便的方式访问以std::bitset<>表示的各种标志:

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 ,
};

可以使用上面的枚举中定义的索引来操纵对应的std::bitset<>

GetBitIndex<short>::BitsetType pollEventMask;

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

上面的两个操作将与以下操作相同:

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

有人声称简短,我个人认为语义级别上的代码易于阅读和使用(只要它不会显着影响性能或占用空间)。

这里可以找到完整的代码示例(请注意,这只是我所做的要点,以使其在另一个项目中进入生产状态)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM