布尔复合赋值中的隐式转换?

Implicit conversions in boolean compound assignment?

我想了解在以下情况下会发生什么:

bool b = false;
float f = 3.14;
char c = 1;
int i = 2;
unsigned int u = 3;
long long int ll = 4;
unsigned long long int ull = 5;

b += f;
b += c;
b += i;
b += u;
b += ll;
b += ull;

b &= f;
b &= c;
b &= i;
b &= u;
b &= ll;
b &= ull;

b <<= f;
b <<= c;
b <<= i;
b <<= u;
b <<= ll;
b <<= ull;

或者换句话说,按照标准做的隐式转换是什么?

其他问题:如果为假设的 bool class 提供的唯一复合赋值签名的形式为:

,结果是否相同?
class bool {bool& operator op=(int x) noexcept;}; // op <=> +,-,&,|...

所有这些情况下的相关转换都是布尔转换,[conv.bool]:

A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true. For direct-initialization (8.5), a prvalue of type std::nullptr_t can be converted to a prvalue of type bool; the resulting value is false.

有两个例外:

b &= f;
b <<= f;

前者,因为[expr.bit.and]:

The usual arithmetic conversions are performed; the result is the bitwise AND function of the operands. The operator applies only to integral or unscoped enumeration operands.

和后者,因为 [expr.shift]:

The operands shall be of integral or unscoped enumeration type and integral promotions are performed.

由于float既不是整数也不是无作用域枚举类型,这两个操作是无效的。


对于您的(我在这里重命名您的 class):

class Bool {Bool& operator op=(int x) noexcept;}; // op <=> +,-,&,|...

我们会陷入三种转换中的一种,具体取决于类型。对于 charbool,我们进行积分促销,[conv.prom]:

A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.
[...]
A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true becoming one.

对于其他整数类型,积分转换,来自[conv.integral]:

A prvalue of an integer type can be converted to a prvalue of another integer type. A prvalue of an unscoped enumeration type can be converted to a prvalue of an integer type.
[...]
If the destination type is signed, the value is unchanged if it can be represented in the destination type; otherwise, the value is implementation-defined.

对于float,一个浮点数转换,来自[conv.fpint]:

A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.

对于复合赋值表达式,右操作数首先转换为左操作数的类型(C++14 5.17 p3):

If the left operand is not of class type, the expression is implicitly converted (Clause 4) to the cv-unqualified type of the left operand.

因此,等效的假设运算符应该采用 bool 参数:

class bool {bool& operator op=(bool x) noexcept;};

这是一个示例,如果您改用 int 会有所不同:

#include <iostream>

struct Bool {
  bool value;

  Bool(bool value) : value(value) { }
  Bool &operator += (int x) noexcept { value += x; return *this; }
};

int main()
{
  Bool fake_bool = false;
  bool real_bool = false;

  fake_bool += 0.1;
  real_bool += 0.1;
  std::cout << fake_bool.value << "\n";
  std::cout << real_bool << "\n";
}

产出

0
1