布尔复合赋值中的隐式转换?
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 <=> +,-,&,|...
我们会陷入三种转换中的一种,具体取决于类型。对于 char
或 bool
,我们进行积分促销,[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
我想了解在以下情况下会发生什么:
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 tofalse
; any other value is converted totrue
. For direct-initialization (8.5), a prvalue of typestd::nullptr_t
can be converted to a prvalue of typebool
; the resulting value isfalse
.
有两个例外:
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 <=> +,-,&,|...
我们会陷入三种转换中的一种,具体取决于类型。对于 char
或 bool
,我们进行积分促销,[conv.prom]:
A prvalue of an integer type other than
bool
,char16_t
,char32_t
, orwchar_t
whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int ifint
can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of typeunsigned int
.
[...]
A prvalue of typebool
can be converted to a prvalue of typeint
, withfalse
becoming zero andtrue
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