隐式转换为布尔值并与布尔文字进行比较
Posted
技术标签:
【中文标题】隐式转换为布尔值并与布尔文字进行比较【英文标题】:Implicit conversion to boolean and comparison with boolean literals 【发布时间】:2014-01-25 13:58:29 【问题描述】:我正在回答this question,关于用户定义的转换到bool
以及如何禁用其他转换的主题:
struct foo
operator bool() const //Explicit overload for bool
return true;
template<typename T>
operator T() const = delete; //Everithing which is not a bool (Everithing which
//does not fit in the explicit overload) would
//resolve to this operator and will fail.
;
int main()
foo f;
bool b = f; //OK
int i = f; //ERROR
char c = f; //ERROR
etc...
后来,OP 问我为什么像 if( f == true )
这样的条件会失败(其中 f
是 foo
。我自己尝试过,这让我感到惊讶,因为与布尔文字的比较导致转换为 int
(禁用)而不是bool
:
int main()
foo f;
if( f ); //OK, converts to bool
if( f == true ); //ERROR: Conversion to int, which has been disabled
prog.cpp:20:12: 错误:使用已删除的函数‘foo::operator T() const [with T = int]' if( f == true); ..................................................... ..................................................... .............................^
我的问题是:布尔文字是否定义为整数(如常见的 C 宏 #define true 1 #define false 0
),如果不是,为什么该比较会导致 int 转换而不是 bool
?
我正在使用启用了 C++11 的 GCC4.8.1 (-std=C++11
)。
Here 是 ideone 的一个例子。
【问题讨论】:
请注意,g++4.8.1 和 clang++3.5 之间的相关示例有一个有趣的区别 这可能是标准中的一个缺陷,请参阅CWG 954(未解决问题),尤其是评论 “某些实现明确选择int
候选者。也许重载解决规则可能是调整为更喜欢 L 和 R 是同一类型的候选人?”(这是我的答案中缺少的部分)
【参考方案1】:
由于foo
是类类型,因此在使用未专门为该类类型定义的运算符时适用特殊规则,请参阅 [over.built]/12
对于每对提升的算术类型
L
和R
,存在以下形式的候选运算符函数LR operator*(L, R); LR operator/(L, R); LR operator+(L, R); LR operator-(L, R); bool operator<(L, R); bool operator>(L, R); bool operator<=(L, R); bool operator>=(L, R); bool operator==(L, R); bool operator!=(L, R);
其中
LR
是L
和R
类型之间通常算术转换的结果。
不使用术语提升的算术类型:这需要提升bool
。
bool
被提升为 int
,参见 [conv.prom]/6(整体提升)
bool 类型的纯右值可以转换为
int
类型的纯右值,false
变为 0,true
变为 1。
所以有表单的候选函数
common_type<L,int> operator==(L, int);
其中L
是提升的算术类型。但是,其中有很多,例如
common_type<int , int> operator==(int , int);
common_type<long , int> operator==(long , int);
common_type<long long, int> operator==(long long, int);
每个都需要用户定义的从foo
到提升类型的转换。我不清楚为什么这不是模棱两可的,因为foo
可以转换为其中任何一个。这也在未解决的问题CWG 954 中进行了描述。
如果有多个非模板转换函数,g++4.8.1 和 clang++3.5 会报告这种歧义。 (需要注意的是,clang 在这里可能有一个错误,请参阅this example,它适用于 g++4.8.1。)
但是,没有候选表格
common_type<bool, int> operator==(bool, int);
因为bool
不是提升的算术类型。因此,从foo
到bool
的转换将不会被选择用于表达式
foo x;
x == true
【讨论】:
我认为答案并不完整。还缺一块。 我已经注意到了。我在等:) @Manu343726 缺少的部分是声明类类型确实需要转换为与提升的bool
相同的类型。它可能有点微妙,例如内置的operator==
要求左右手的类型相同。
@dyp 出现的另一个问题是bool operator==(bool,bool)
是否存在或者true==true
是否会导致对bool operator==(int,int)
的调用。
@Manu343726 这些规则继承自C;事实上,他们试图复制硬件的行为。整体促销不仅限于bool
s,还适用于char
s 和short
s 等。例如,short s = 1, t = 2; auto x = s+t;
将x
声明为int
。【参考方案2】:
类型 bool 不是 #在 C++ 中定义。我认为比较提升为 int 并需要 int 转换。
【讨论】:
这就是我的想法,我知道布尔文字不是#define
d。只是这种行为让我感到惊讶。有没有人提到标准这么说?
bool 转换为 int 用于比较。我没有标准的参考(需要下载,嗯……)但我很确定 bool => int 加上类 foo 缺少 int 转换是错误的根源。 【参考方案3】:
让我们在这里做一个快速测试:
template <typename T>
struct OutputType;
int main()
OutputType<decltype(true)> a;
至少 ideone 在此处输出 true
的类型为 bool
:http://ideone.com/Gm653T
但是:
bool 类型可以转换为 int,值 false 变为0,true 变为 1。
来源:cppreference
而我的猜测是,这里正是发生了这样的促销活动
【讨论】:
以上是关于隐式转换为布尔值并与布尔文字进行比较的主要内容,如果未能解决你的问题,请参考以下文章