15

次のコードを検討してください。

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

の型はdeclval(bool) ? declval(float) : declval(double)doubleC++ 標準 [expr.cond] に従います。

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

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

?:または、最初のオペランドがコンパイル時の定数式である場合に最適化を許可するステートメントはありますか?

4

2 に答える 2

14

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

RTTIを使用して、少なくともclangとの両方g++が標準に準拠していることを確認しd、このプログラムへの出力として (たとえば double) を与えることができます。

#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の型特性を使用する別の方法

#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ます。

于 2013-06-22T20:51:26.620 に答える
10

C++ コンパイラは、適合するプログラムの「観察可能な動作」を変更しない限り、適切と思われるように最適化できます (§1.9p1、いわゆる「as if」ルール)。

たとえば、特定のプラットフォームで、1.0 による乗算がトラップの可能性のない恒等変換であることがわかっている場合、乗算を実際に実行する必要はありません。(NaN 値を 1.0 で乗算するとトラップされる可能性があるため、これは特定のアーキテクチャに当てはまる場合とそうでない場合があります。ただし、コンパイラは、同じ状況で同じトラップを生成する他の操作で乗算を置き換えることもできます。 .)

トラップがなく、1.0 による乗算が恒等変換であると仮定すると、関数の本体全体をf削除できます。標準では、値のセットがfloat値のセットのサブセットdouble(おそらく同じセット) であることを要求しているためです。したがって、float->double->float の往復は、元の値またはトラップに戻る必要があります。(§3.9.1p8: 「型の値のセットは、型floatの値のセットのサブセットですdouble」。§4.8p1: 「浮動小数点型の prvalue は、別の浮動小数点型の prvalue に変換できます。ソース値が宛先タイプで正確に表現できる場合、変換の結果はその正確な表現になります。")

したがって、はい、最適化が可能な場合があります。?:ただし、型が観測可能である場合 (たとえば、式がテンプレート演繹または のオペランドとして使用される場合) は、式の型には影響しませんdecltype

于 2013-06-22T22:15:45.160 に答える