传统的 Flag 运算符有哪些?

Which are the conventional Flag operators?

我定义了一个枚举,用于在变量中存储标志。目的是能够设置多个标志,并能够检查设置了哪些标志。

为此,我需要两个操作:一个是找出 a 是否在 b 中,另一个是找出 a 是否在 中不是 b 中的 。我使用运算符重载来实现它们。我随便选了<=!=

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

这很好用。例如:

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

我随便选了<=!=。我知道它们通常具有完全不同的含义。所以我想知道:

你的代码的大多数读者(甚至可能是你未来的自己)会感到很困惑,因为你赋予运算符的含义与标准运算符不一致。例如:

  • !(a <= b) 预计与 a>b
  • 相同
  • !(a != b) 预计与 a==b
  • 相同
  • flags1 != flags3 不再意味着在两个变量中设置了完全相同的标志

因此,根据 principle of least astonishment,我强烈反对您的选择。

标志操作符的常见做法是使用|设置标志,&结合~重置标志,&测试标志.但这是完成的,假设可预测的按位操作,而不是像您那样的更高级别的接口。

在你的情况下,我建议使用函数而不是运算符,并让函数名称清楚地表达你的意图(例如 is_included())。我什至建议考虑使用成员函数 enum classes 以获得更好的封装。

由于您似乎将 Flag 变量视为一组组合的独立标志,如果您正在寻找一致且已知的命名方案,则可以从 std::set 接口中获得启发(例如 insert()find()contains()merge() 等...)。