枚举位域容器类

发布于 2024-07-12 21:48:51 字数 1454 浏览 8 评论 0原文

我试图编写一个小类来更好地理解 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: 

Im trying to write a small class to better understand bit flags in c++. But something isnt working out. It prints the wrong values. Where is the problem? Have I misunderstood how to add flags? Or check if the bit field has them?

Heres the code:

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

Output of program:

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: 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

心是晴朗的。 2024-07-19 21:48:51

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

但是,像这样执行 O(1) 操作:

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

There's a bug in your remove_flag() method, it should be flags |= i;

But, do it O(1) like this:

void remove_flag(flag f) { m_flags &= ~f; }
浅浅淡淡 2024-07-19 21:48:51

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

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

has_flag() and remove_flag() are wrong. They should go like this:

bool has_flag(flag f) { return !!(m_flags & f); }
void remove_flag(flag f) 
{
    m_flags &= ~f;
}
咋地 2024-07-19 21:48:51

我个人会使用 std::vector< 布尔> 处理标志,因为它是将布尔值打包成位的专业化。

但是:

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

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

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

personally I would use std::vector< bool > to handle flags, since it is a specialization that packs bools into bit.

However:

I think your remove flag is a bit complex, try this instead

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

Edit:
A comment asked why I just didn't do m_flags &= ~f. I took the question as a 'learner' question not an optimization question. I show how to make his code correct, not fast.

儭儭莪哋寶赑 2024-07-19 21:48:51

每个人都已经明白了这一点:flag &= ~f;

你可以看看我之前的发布。

has_flag():如果 f 中的所有位都已设置,您是否希望返回 true? 或者是否至少设置了其中一项? 这就是flags&f==f 之间的区别 与 标志&f !=0。

您可能会考虑#include和 cout << 十六进制 <

枚举可以位于类 Holder 内部。

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

然后您可以使用 Holder::A 而不是 A

您可能希望使用 for(i=0;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 美元。

Everyone has already nailed this: flag &= ~f;

You might look at my earlier posting.

has_flag(): Are you looking to return true if all the bits in f are set? Or if at least one of them is set? It's the difference between flags&f==f   vs   flags&f !=0.

You might consider #include <iomanip> and cout << hex <<m_flag <<dec. (Hex to bit conversion can be more easily done in your head.)

The enum could be inside class Holder.

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

You would then use Holder::A instead of A.

You may want to use for(i=0;i<N;i++) if has_flag(1<<i) ...

You may want your add_flag/has_flag/remove_flag methods to take an int rather than the enumerated type. That gets rid of a lot of casting. If you don't want to support all possible int values, a validation method and rejection path could be used. By the way, there's nothing stopping me from calling add_flag(flag(5736)). And you are casting to enum_flag quite frequently already.

You may want to use mFlag rather than m_flag. It's your choice. But when you look at code like m_x*m_y-m_z*m_y-m_x*m_z , depending on your font, it can be easy to mistake _ for -. (Or vice versa.)

Similarly, consider addFlag rather than add_flag. For something like this it doesn't matter. But when you have a long descriptive name, those underscores start to add up, using up linespace. The temptation is then to abbreviate the name, making your code more obtuse.

Just my $0.02.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文