枚举位域容器类

时间:2009-02-07 16:09:49

标签: c++ enums bit-fields bitflags

我试图编写一个小类来更好地理解c ++中的位标志。但有些事情没有成功。它打印错误的值。问题出在哪儿?我误解了如何添加标志吗?或者检查位字段是否包含它们?

下面是代码:

#include <iostream>

enum flag
{
    A = 1, B = 2, C = 4
};

class Holder
{
public:
    Holder() : m_flags(A) {}
    ~Holder() {}

    void add_flag(flag f) { m_flags |= f; }
    bool has_flag(flag f) { return ((m_flags&f)==f); }
    void remove_flag(flag f) 
    {
        unsigned int flags = 0;
        for (int i = 1; i<=(int)C; i *= 2)
        {
            if ((flag)i!=f && has_flag(f))
                flags |= f;
        }
        m_flags = flags;
    }

    void print()
    {
        std::cout << "flags are now: " << m_flags << " | holding: "; 
        for (int i = 1; i<=(int)C; i *= 2)
        {
            if (has_flag((flag)i))
                std::cout << i << " ";
        }
        std::cout << std::endl;
    }

private:
    unsigned int m_flags;
};

int main()
{
    Holder h;
    h.print(); // should print 1

    h.add_flag(B);
    h.print(); // should print 1 2

    h.remove_flag(A);
    h.print(); // should print 2

    h.add_flag(C);
    h.print(); // should print 2 4

    h.remove_flag(B);
    h.print(); // should print 4
}

节目输出:

flags are now: 1 | holding: 1 
flags are now: 3 | holding: 1 2 
flags are now: 1 | holding: 1 
flags are now: 5 | holding: 1 4 
flags are now: 0 | holding: 

4 个答案:

答案 0 :(得分:3)

你的remove_flag()方法有一个错误,它应该是flags | = i;

但是,这样做O(1):

void remove_flag(flag f) { m_flags &= ~f; }

答案 1 :(得分:3)

has_flag() remove_flag()错误。它们应该是这样的:

bool has_flag(flag f) { return !!(m_flags & f); }
void remove_flag(flag f) 
{
    m_flags &= ~f;
}

答案 2 :(得分:3)

我个人会使用std :: vector&lt; bool&gt;处理标志,因为它是一个将bool打包成bit的专业化。

然而:

我认为你的删除标志有点复杂,试试这个

void remove_flag( flag f ) 
{
   if ( has_flag( f ) == true )
   {
      m_flags ^= f;   // toggle the bit leaving all other unchanged
   } 
}

编辑: 评论问为什么我没有do m_flags &= ~f。我将问题视为“学习者”问题而不是优化问题。我展示了如何使他的代码正确,而不是快速。

答案 3 :(得分:0)

每个人都已经钉了这个:flag&amp; =〜f;

You might look at my earlier posting.

has_flag():如果设置了f中的所有位,是否要返回true?或者,如果至少设置了其中一个?这是flag&amp; f == f vs flags&amp; f!= 0。

之间的区别

您可以考虑#include&lt; iomanip&gt;和cout&lt;&lt;十六进制&lt;&lt; m_flag&lt;&lt; dec。 (可以更容易地在头脑中完成十六进制到位转换。)

枚举可以在班主持人内部。

class Holder
{
public:
  enum flag { A=1, B=2, C=4; };
...
};

然后您将使用 Holder :: A 而不是 A

如果has_flag(1&lt;&lt;&lt; i)...

,您可能想要使用for(i = 0; i&lt; N; i ++)

您可能希望add_flag / has_flag / remove_flag方法采用int而不是枚举类型。这摆脱了很多铸造。如果您不想支持所有可能的int值,可以使用验证方法和拒绝路径。顺便说一句,没有什么能阻止我调用add_flag(flag(5736))。而且你已经经常使用enum_flag了。

您可能希望使用mFlag而不是m_flag。这是你的选择。但是当你查看像m_x * m_y-m_z * m_y-m_x * m_z这样的代码时,根据你的字体,很容易将_误认为 - 。 (反之亦然。)

同样,请考虑addFlag而不是add_flag。对于这样的事情并不重要。但是当你有一个很长的描述性名称时,那些下划线开始加起来,使用了行空间。然后诱惑就是缩写名称,使你的代码更加迟钝。

只需我0.02美元。