隐式转换为布尔值并与布尔文字进行比较

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 ) 这样的条件会失败(其中 ffoo。我自己尝试过,这让我感到惊讶,因为与布尔文字的比较导致转换为 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

对于每对提升的算术类型 LR,存在以下形式的候选运算符函数

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);

其中LRLR 类型之间通常算术转换的结果。

不使用术语提升的算术类型:这需要提升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 不是提升的算术类型。因此,从foobool 的转换将不会被选择用于表达式

foo x;
x == true

【讨论】:

我认为答案并不完整。还缺一块。 我已经注意到了。我在等:) @Manu343726 缺少的部分是声明类类型确实需要转换为与提升的bool 相同的类型。它可能有点微妙,例如内置的operator== 要求左右手的类型相同。 @dyp 出现的另一个问题是bool operator==(bool,bool) 是否存在或者true==true 是否会导致对bool operator==(int,int) 的调用。 @Manu343726 这些规则继承自C;事实上,他们试图复制硬件的行为。整体促销不仅限于bools,还适用于chars 和shorts 等。例如,short s = 1, t = 2; auto x = s+t;x 声明为int【参考方案2】:

类型 bool 不是 #在 C++ 中定义。我认为比较提升为 int 并需要 int 转换。

【讨论】:

这就是我的想法,我知道布尔文字不是#defined。只是这种行为让我感到惊讶。有没有人提到标准这么说? 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

而我的猜测是,这里正是发生了这样的促销活动

【讨论】:

以上是关于隐式转换为布尔值并与布尔文字进行比较的主要内容,如果未能解决你的问题,请参考以下文章

隐式类型转换

JavaScript:隐式类型转换

JavaScript:隐式类型转换

Js隐式转换

“IsFalse”和“IsTrue”基本上只是隐式转换为布尔值吗?

Objective-C 对象字面量的隐式布尔转换总是计算为真 ios