【问题标题】:Implicit conversion of stream to bool流到布尔的隐式转换
【发布时间】:2017-04-11 06:02:08
【问题描述】:

拿这个玩具代码:

#include <iostream>
#include <fstream>

int main() {

    std::ifstream is;
    // perform read
    // ...
    if (!is) // works
        std::cout << "fail";
    if( is == false)  // error C2678
        std::cout << "fail";

    return 0;
}

你会得到以下违反直觉的结果:if(!is) 编译,if(is==false) 给出

错误 C2678:二进制“==”:未找到采用左手的运算符 'std::ifstream' 类型的操作数(或没有可接受的转换)

(对于 VS2015 - gcc 和 clang 中的类似错误)。

标准说(根据this answer):

依赖于隐式布尔转换的有效 C++ 2003 代码将 不符合本国际标准。此类转换 发生在以下情况:

  • 将值传递给接受 bool 类型参数的函数;

  • 使用 operator== 比较 false 或 true;

  • 从返回类型为 bool 的函数返回值;

  • 通过聚合初始化初始化 bool 类型的成员;

  • 初始化一个 const bool& 将绑定到一个临时对象。

据我所知,if(is==false) 明确要求失败,但为什么 if(!is) 没有?它不符合“隐式布尔转换”的条件吗?

是否有意从标准中列出的案例中省略了这种转换为布尔的情况?也许是无意的遗漏?


编辑: 这段代码也失败了:

int main() {

    std::ifstream is;
    // perform read
    // ...
    if (is) // works
        std::cout << "success";
    if( is == true)  // error C2678
        std::cout << "success";

    return 0;
}

这里操作符的存在!() 是无关紧要的。

【问题讨论】:

    标签: c++ c++11 language-lawyer


    【解决方案1】:

    std::ifstream 继承的operator boolmarked explicit

    explicit operator bool() const; (2)(C++11 起)

    这意味着没有没有隐式转换为 bool,即所有这些表达式都失败了:

    bool result = is;    // fails
    bool b = is == true; // fails
    if (is == false);    // fails
    while (is == false); // fails
    

    如果您想知道为什么if (is) 和类似的语句会编译,那是因为ifwhile 等有特殊的转换规则:explicit 关键字被忽略!

    if (is);                        // ok
    while (is)                      // ok
    bool b = static_cast<bool>(is); // ok
    

    请注意,最后一种情况会编译,因为您明确想要一个布尔值。

    从技术上讲,!is 可以正常工作,因为您明确想要一个布尔值,但 std::ifstream 有一个继承的 operator!,因此调用该运算符而不是默认的 operator!对布尔值进行操作:

    if (!is);     // ok
    bool b = !is; // ok
    

    【讨论】:

    • 它可以potentially work 没有明确的operator!
    • 我也认为它可以像is &amp;&amp; true 那样工作
    • @Rakete1111 谢谢。你能引用这个标准吗?您对 为什么 if/while 子句忽略显式关键字有任何见解吗?这肯定会让事情变得更加混乱(至少对我而言)。
    • @OfekShilon 查找 contextual conversion to bool。那就是if等的控制表达式的上下文。在这些上下文中考虑显式运算符 bool。
    【解决方案2】:

    !is 有效,因为 std::basic_ios(流的基类之一)定义了 operator!()

    所以这根本不是转换,而是对is.operator!()的调用。

    【讨论】:

    • 你是对的,但这不是根本原因。我已经编辑了问题以反映它:if(is)if(!is) 一样成功
    • 是的,因为std::basic_ios 也有一个operator bool() 来补充operator!()
    • 运算符标记为explicit,这是混淆的根源。原来在这种情况下显式限定符被忽略了
    • 不,不是。这正是 explicit operator bool() 设计工作的地方:“某些语言结构要求将表达式转换为布尔值。出现在这种上下文中的表达式 e 据说在上下文中被转换为bool 并且当且仅当声明 bool t(e); 是格式正确的,对于某些发明的临时变量 t 是格式正确的"
    • explicit 没有在此处提及。我错过了什么吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-11
    • 2014-09-07
    • 2015-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-03
    相关资源
    最近更新 更多