2013-06-22 5 views
15

ある場合は、次のコードを検討:タイプ「?」最初のオペランドは、定数式

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

declval(bool) ? declval(float) : declval(double)のタイプは、C++標準の[expr.cond]に従ってdoubleあります。

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

またはケースで最適化が?:の最初のオペランドがコンパイル時定数式であることができ文があります:

が、これは上記のコードと等価なければならないことを意味していますか?

+0

「難読化されたC++コンテスト」からですか? 「本当ですか? 1.0f:... 'は常に1.0fと評価されますが、1.0fで乗算するのは意味がありますか? –

+1

@ ott--これは、質問が実際に何についてであるかにだけ答えが集中するような方法で質問を表現する良い方法です。たとえそれが問題のポイントではないとしても、他のどんな定数でも丸めに焦点を当てた答えが得られるはずです。 – hvd

+4

式は常に1つの型しか持てないので、 'something? a:bは、「何か」が何であれ、常に同じでなければならず、同じでなければならない。 – Xeo

答えて

10

C++コンパイラは、準拠しているプログラムの「観察可能な動作」(§ 1.9p1、いわゆる「if if」ルール)を変更しない限り、最適と見なして最適化することができます。

例えば、1.0の乗算が罠の可能性のない恒等変換であることが知られているプラ​​ットフォームでは、乗算は実際には実行する必要はありません。 (これは、NaNの値に1.0を乗算するとトラップする可能性があるため、特定のアーキテクチャでは当てはまらないかもしれませんが、コンパイラは同じ状況下で同じトラップを生成する他の演算。

トラップが存在せず、1.0の乗算が恒等変換であると仮定すると、標準でfloatの値の集合がセットのサブセットであることが要求されるため、関数fの全身は削除できます。 double値(おそらく同じセット)。したがって、float-> double-> floatラウンドトリップは、元の値またはトラップに戻らなければなりません。 (§ 3.9.1p8: "タイプfloatの値のセットは、タイプdoubleの値のサブセットです。" § 4.8p1: "浮動小数点型のprvalueは別の浮動小数点のprvalueに変換できますソース値が宛先タイプで正確に表現できる場合、変換の結果は正確な表現です。 ")

はい、最適化が可能です。しかし、タイプが観測可能な場合(例えば、式がテンプレート控除に使用される場合、またはオペランドがdecltypeの場合)、?:式のタイプには影響しません。

14

はい、上記のコードが同等であることを意味します。

#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を使用して別の方法を:私たちはこのプログラムへの出力として(ダブルなど)少なくともclangg++両方が標準に準拠していることを確認し、dを与えることができRTTIを使用

#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

関連する問題