gpt4 book ai didi

c++ - 枚举的复合赋值运算符真的应该根据它们相关的算术运算符来定义吗?

转载 作者:行者123 更新时间:2023-11-28 04:09:19 24 4
gpt4 key购买 nike

通常,重载运算符时,the arithmetic operators (including bitwise operators) are defined in terms of the associated compound assignment operators (例如,operator+operator| 通常依赖于 operator+=operator|=)。

class SomeClass {
SomeType data;
// ...

public:
SomeClass& operator+=(const SomeClass& other) {
data += other.data;
return *this;
}
friend SomeClass operator+(SomeClass l, const SomeClass& r) { return l += r; }

friend SomeClass& operator|=(SomeClass& l, SomeClass r) {
l.data |= r.data;
return l;
}
friend SomeClass operator|(SomeClass l, SomeClass r) { return l |= r; }
};

但是,当涉及到enum(无论是无作用域还是enum class)时,逻辑通常是相反的,the preferred solution often being to instead define compound assignment operators in terms of the arithmetic operators 1.

using Underlying = uint8_t;

enum class SomeEnum : Underlying {
A_VALUE = 0b0000'0001,
B_VALUE = 0b0000'0010,
// ...
H_VALUE = 0b1000'0000,

CLEAR_ALL = 0,
SET_ALL = static_cast<uint8_t>(-1),
};

// Arithmetic first.
constexpr SomeEnum operator|(SomeEnum l, SomeEnum r) {
return static_cast<SomeEnum>(static_cast<Underlying>(l) | static_cast<Underlying>(r));
}
constexpr SomeEnum& operator|=(SomeEnum& l, SomeEnum r) { return l = l | r; }

// Compound assignment first.
constexpr SomeEnum operator+=(SomeEnum& l, SomeEnum r) {
Underlying ul = static_cast<Underlying>(l);
ul += static_cast<Underlying>(r);
return l = static_cast<SomeEnum>(ul);
}
constexpr SomeEnum operator+(SomeEnum l, SomeEnum r) { return l += r; }

1:虽然问题的答案提供了根据 operator| 定义 operator|= 和定义 operator| 的示例就 operator|= 而言,两个答案的发布时间都在半小时内(因此曝光率几乎相同),前者的赞成票要多得多。这表明到目前为止它是更受欢迎的解决方案。


现在,我明白了采用这种方法的原因:如果我们反过来定义算术运算符,代码会明显更清晰,特别是如果我们还希望编译时可用。然而,它也违背了几乎(?)在其他任何地方使用的模式,这让 IMO 看起来有点可疑(主要是因为它违反了最小惊讶原则)。

鉴于此,我不禁想知道:应该我们在这里翻转一下吗?简单的好处是否值得打破“a += b 通常比 a + b 更有效并且应该尽可能优先使用”的不言而喻的保证2?

简单地说,如果为枚举定义运算符3,我们应该根据关联的算术运算符而不是相反的方式来定义复合运算符,就像是常见的推荐吗?

2:参见 first link 上的脚注 #3 .

3:通常是按位运算符,但我想笼统地说。

最佳答案

在这里谈论效率是错误的。任何好的编译器都会将它们编译成同样的东西。 gcc does at -O1 ,而且我怀疑大多数编译器也会这样做。

因为优化最终会得到同样的结果:

Underlying ul = static_cast<Underlying>(l);
ul += static_cast<Underlying>(r);
return l = static_cast<SomeEnum>(ul);

Underlying ul;
(ul = static_cast<Underlying>(l)) += static_cast<Underlying>(r);
return l = static_cast<SomeEnum>(ul);

Underlying ul;
return l = static_cast<SomeEnum>((ul = static_cast<Underlying>(l)) += static_cast<Underlying>(r));

return l = static_cast<SomeEnum>(static_cast<Underlying>(l) + static_cast<Underlying>(r));

return l = operator+(l, r);

根据 operator@= 为枚举实现 operator@ 没有意义,因为您将它复制到它的底层类型,执行操作,然后将其复制回来并分配给拷贝。在类中,使用 A @= B 而不是 A = A @ B 时(理论上)应该有更少的复制/移动。

关于c++ - 枚举的复合赋值运算符真的应该根据它们相关的算术运算符来定义吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58151298/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com