2013-06-22 22 views
15

考慮下面的代碼:根據C++標準[expr.cond]類型的「:」如果第一操作數是常量表達式

void f(float x) 
{ 
    x * (true ? 1.f : 0.0); 
} 

類型的declval(bool) ? declval(float) : declval(double)double

這是否意味着上面的代碼具有等同於:

void f(float x) 
{ 
    double(x) * 1.0; 
} 

還是有允許的情況下,優化的?:第一個操作數是編譯時間常數表達式語句?

+0

這是來自'混淆的C++比賽'嗎?真的? 1.0f:...'總是評估爲1.0f,但與1.0f相乘有意義嗎? –

+1

@ ott--這是用這樣一種方式來表達問題的好方法,即答案只會關注問題的實質。幾乎任何其他常數都可能得到關於四捨五入的答案,儘管這不是問題的關鍵。 – hvd

+4

一個表達式總是隻能有一個類型,所以'something?的類型? a:b'無論什麼「東西」,都必須始終如一。 – Xeo

回答

10

只要它不改變合格程序的「可觀察行爲」(§ 1.9p1,即所謂的「彷彿」規則),C++編譯器就可以對其進行優化。

例如,如果一個給定平臺上已知的是,由1.0相乘是沒有電勢捕獲恆等變換,則乘法實際上並不需要被執行。 (對於給定的體系結構,這可能會也可能不會,因爲乘以NaN值可能會陷入1.0,但編譯器也可以用相同情況下產生相同陷阱的任何其他操作代替乘法)

如果沒有陷阱,並假設乘以1.0是一個恆等變換,則可以消除函數f的整個主體,因爲該標準要求該值集合是該集合的子集double值(可能是同一組)。因此,float-> double-> float往返必須返回到原始值或陷阱。 (§ 3.9.1p8:「float類型的值的集合是double類型的值集合的子集」§ 4.8p1:「浮點類型的值可以轉換爲另一個浮點的值如果源值可以在目標類型中準確表示,則轉換結果就是該確切表示。「)

所以,是的,可以進行優化。但是,如果該類型是可觀察的(例如,如果該表達式要用於模板演繹或作爲decltype的操作數),那麼這不會影響表達式的類型。

14

是的,它意味着在上面的代碼是等價的。

使用RTTI我們可以檢查至少兩個clangg++是標準的符合性,並給予d(例如雙)作爲輸出到這個程序:

#include <iostream> 
#include <typeinfo> 

int main() { 
    float x = 3.; 
    auto val = x * (true ? 1.f : 0.0); 
    std::cout << typeid(val).name() << std::endl; 
} 

並採用C++ 11 type traits的替代方式

#include <iostream> 
#include <typeinfo> 

int main() { 
    float x = 3.; 
    auto val = x * (true ? 1.f : 0.0); 
    std::cout << std::boolalpha << 
     std::is_same<decltype(val), double>::value << std::endl; 
} 

輸出true

相關問題