3

セットアップ

MotionBuilder というアプリケーションの API を使用しています。MotionBuilder プロパティの値にアクセスするには、実際に表すデータ タイプに関係なく、double 変数に読み込みます。

以下は、スカラー プロパティの値を評価するために作成したユーティリティ関数です。

template <typename DataT>
inline DataT GetScalar(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
    double data = 0.0;
    prop.GetData(&data, sizeof(data), evaluateInfo);
    return static_cast<DataT>(data);
}

このようにして、初期化されていないバッファとキャストが散らばるコードを散らかす複数行の混乱の代わりにGetScalar<float>(camera.Roll, evaluateInfo)orを書くことができます。GetScalar<bool>(camera.Visibility, evaluateInfo)

私はVisual Studioでコンパイルし、/W4すべての警告が表示されたら対処しています。を使用するGetScalar<bool>と、コンパイラはC4800 警告を生成します

'double' : forcing value to bool 'true' or 'false' (performance warning)

コンパイラが を作成GetScalar<bool>すると、double から bool への static_cast が発生しますが、これは明らかに気に入らないようです。私の本来の目的は、単一のテンプレート関数で複数の型 (bool、float、double など) を処理することだったので、通常の!= 0.0.

この警告に対処するには、2 つのオプションがあります。

オプション1

キャストはまさに私がやりたかったことをしているので、プラグマを使用して警告を直接抑制することができます。

template <typename DataT>
inline DataT GetScalar(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
    double data = 0.0;
    prop.GetData(&data, sizeof(data), evaluateInfo);
#pragma warning (push)
#pragma warning (disable: 4800) // Don't complain about casting to bool
    return static_cast<DataT>(data);
#pragma warning (pop)
}

オプション 2

ケースGetScalarを処理するための特殊化を追加できます。bool

template <>
inline bool GetScalar<bool>(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
    double data = 0.0;
    prop.GetData(&data, sizeof(data), evaluateInfo);
    return data != 0.0;
}

質問

static_cast<bool>(x)一部の double x については、 とまったく同じであると思いますx != 0.0。実際、リリース モードでコンパイルされた簡単なテストでは、どちらの場合も同じアセンブリ出力が得られます。では、なぜ C4800 は自身を「パフォーマンス警告」と呼ぶのでしょうか? 上記の 2 つのオプションは機能的に同じですか? スタイルの問題になるとしたら、最高の衒学者の帽子をかぶった後、どのオプションが好みですか?

4

4 に答える 4

4

boolの場合、キャストよりも 0 との比較の方が読みやすいと思います。boolまた、たとえここで機能したとしても、数値型に特化した同じ実装を持つ関数を持つことが意味的に意味があるかどうかも疑問です。

一般的。あなたの特定のケースでは、統一されたテンプレートを使用することは問題ないと思います。コードの重複を回避できれば、それは利点です。DataTどちらかといえば、関数全体ではなく、部分へのキャスト用の関数の特殊化のみを作成する可能性があります。

template <typename T>
T convertTo(double d) { return static_cast<T>(d); }

template <>
double convertTo<bool>(double d) { return d != 0.0; }

template <typename DataT>
inline DataT GetScalar(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
    double data = 0.0;
    prop.GetData(&data, sizeof(data), evaluateInfo);
    return convertTo<DataT>(data);
}

または、警告を選択的に無効にすることもできますが、そうする場合は、ここでこれが必要な理由をコメントで説明してください。

于 2013-07-10T21:13:12.730 に答える
4

これは警告であり、この変換のパフォーマンスに問題がある可能性があることを示しています。あなたは変換をしたいので、それをしてください。何の役にも立たない警告に対して、入念な回避策を書いて時間を無駄にしないでください。

于 2013-07-10T21:54:47.843 に答える
4

特定のセットアップに最適なソリューションが何であるかはわかりませんが(静的キャストは完全に問題ないと思いますbool)、分岐を処理する一般的な方法は、個々の操作ごとに個別の特性を作成することです。あなたの場合、それは「convert_to_bool」です:

template <typename Out>
struct converter
{
    static Out from_double(double x)
    {
        return static_cast<Out>(x);
    }
};

template <>
struct converter<bool>
{
    static bool from_double(double x)
    {
        return x != 0;
    }
};

これで、次を使用できます。

return converter<DataT>::from_double(data);

このようにして、メイン テンプレートで発生し、特定の型に対して特別な処理が必要なすべての状況を、メイン テンプレートを分岐することなく処理できます。

于 2013-07-10T21:14:46.057 に答える
0

これは、キャストの関数表記バージョンを使用するまれなケースの 1 つですstatic_cast。この形式のキャストは、「自分が何をしているかを知っている」ことを効果的に伝えるため、コンパイラは警告を出しません。

template <typename DataT>
inline DataT GetScalar(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
    double data = 0.0;
    prop.GetData(&data, sizeof(data), evaluateInfo);
    return DataT(data);
}

一般に、C++ でこのタイプのキャストを使用すると、意味のある警告が抑制される可能性があるため、注意してください。オーバーフローの処理を気にしない場合に、算術型 ( intdouble、 など) の間でキャストするときに警告を抑制するためにのみ使用します。enum

于 2013-07-11T12:18:51.853 に答える