2017-01-10 79 views
11

以下代碼在Visual Studio 2008中編譯但在Visual Studio 2013及更高版本中失敗。評估流操作符>>作爲布爾值

std::string str("foo"); 
std::stringstream ss(str); 
float f = 0; 

if ((ss >> f) == false) 
    std::cout << "Parse error\n"; 

該錯誤消息是

錯誤C2678:二進制 '==':沒有操作員發現它接受一個左手 的操作數類型的 '標準:: basic_istream>'(或 有沒有可接受的轉化率)

,並通過改變被成功固定如下:

if (!(ss >> f)) 
    std::cout << "Parse error\n"; 

我對此不甚瞭解。我的問題是,涉及哪些操作員或角色或者ios標誌可以使流讀取首先被評估爲布爾值,然後爲什麼缺少operator==會打破它?

回答

16

自C++ 11以來,兩種行爲已發生變化。

  1. std::basic_ios::operator bool改變行爲。

    operator void*() const;   (1) (until C++11) 
    explicit operator bool() const; (2) (since C++11) 
    

    注意因爲C++ 11 operator bool()被聲明爲explicit;但是對於if ((ss >> f) == false),ss(即返回值(ss >> f))需要隱式轉換爲bool(與false比較),這是不允許的。

  2. 空指針常數的定義已更改。

    之前C++ 11 operator void*()可以使用,它不是explicit(C++ 11有沒有這樣的explicit user-defined conversion之前),和前C++ 11 the null pointer constant定義爲:

    積分常數計算結果爲零 (直到C++ 11),這意味着false整數型

    的表達右值可以作爲一個空指針常數。因此ss可以隱式轉換爲void*,然後與false(作爲空指針)進行比較。

    從C++ 11,空指針常數定義爲:

    的文字與零值,或類型的prvalue整數std::nullptr_t (因爲C++ 11)

    false不再;它不是integer literal

因此,由於這兩個變化,if ((ss >> f) == false)在C++ 11及更高版本中將不起作用。

另一方面,if (!(ss >> f))正常工作,因爲它有std::basic_ios::operator!(在C++ 11之前和之後)。

bool operator!() const; 

返回true如果在相關流發生錯誤。 具體而言,如果在rdstate()中設置了badbit或failbit,則返回true

順便說一句:由於C++ 11,即使沒有std::basic_ios::operator!explicit operator bool() const也可以使if (!(ss >> f))工作良好,因爲在contextual conversion上下文中,explicit用戶定義的轉換被認爲是;即ss可以根據情況轉換爲booloperators !

+0

值得一提的是,即使'operator bool'被標記爲'explicit',由於針對bool運算符的顯式轉換的少數例外之一,if(foo)或if(!foo)示例[here](http://coliru.stacked-crooked.com/a/e884a7adaf92a472)。我相信這被稱爲**上下文轉換**,請參閱[此博客文章](http://chris-sharpe.blogspot.ca/2013/07/contextually-converted-to-bool.html)。 – vsoftco

+1

NULL是一個擴展爲* a *空指針常量的宏,而不是「空指針常量」,也不是「空指針常量」的同義詞。 –