【问题标题】:Which are the conventional Flag operators?哪些是传统的标志运营商?
【发布时间】:2018-11-10 13:00:37
【问题描述】:

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

为此,我需要两个操作:一个是找出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

我随意选择了&lt;=!=。我知道它们通常具有完全不同的含义。所以我想知道:

  • 是否存在使用其他运算符表示这两个操作的普遍接受的做法?

  • 或者使用函数而不是运算符重载会更好?

【问题讨论】:

  • 通常不鼓励为与现有含义完全不相似的运算符编造自己的含义,因为这违反了最小惊讶原则。 (有些人甚至说 iostreams operator&lt;&lt;operator&gt;&gt; 是一个错误,尽管在这一点上它们已经很成熟并且普遍被理解。)我会使用命名函数。
  • @MatthieuBrucher 枚举类型保证能够在最大枚举值之后存储最接近 2 减一幂的值,因此实际上将枚举值的按位或组合强制转换为枚举类型。
  • @aschepler 这实际上是对一个完全有效的问题的一个很好的答案。就这样发布,我会更新
  • 是的,谢谢,这就是我真正需要知道的一切。如果作为答案发布,我会接受。
  • @bur 有一些反对票和接近票可能是因为有些人不明白你对旗帜和运营商的意思。我稍作编辑以使其更清晰。如果我弄错了,请随时纠正。

标签: c++ enums operator-overloading flags


【解决方案1】:

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

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

因此,根据 principle of least astonishment 的说法,我强烈建议您不要选择。

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

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

由于您似乎将Flag 变量视为一组组合的单独标志,如果您正在寻找一致且已知的命名方案(例如insert()、@ 987654337@、contains()merge() 等...)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-12
    • 1970-01-01
    • 2020-11-22
    • 1970-01-01
    相关资源
    最近更新 更多