10

テンプレートクラスメソッド内に定数数値リテラルを含めるための解決策を見つけようとしています。float 型または double 型で使用する数学テンプレート クラスをいくつか作成しています。問題は、リテラルがデータ型によって異なることです (たとえば、float の場合は "0.5f"、double の場合は "0.5")。これまでのところ、私は2つの解決策を考え出しています。最初のコードの仮説コード:

template <typename T>
class SomeClass
{
    public:
        T doSomething(T x);
};

template <>
float SomeClass<float>::doSomething(float x)
{
    float y = 0.5f;
    /*
     * Do computations...
    */
    return x;
}

template <>
double SomeClass<double>::doSomething(double x)
{
    double y = 0.5;
    /*
     * Do computations...
    */
    return x;
}

上記のアプローチでは、使用されるすべての型のメソッド全体を強制的に書き換えます。

別のアプローチ:

template <typename T>
class SomeClass
{
    public:
        T doSomething(T x);

    private:
        T getValue();
};

template <typename T>
T SomeClass<T>::doSomething(T x)
{
    T y = getValue();
    /*
     * Do computations...
    */
    return x;
}

template <>
float SomeClass<float>::getValue()
{
    return 0.5f;
}

template <>
double SomeClass<double>::getValue()
{
    return 0.5;
}

これは、特定の型に対して同じメソッドを複数回記述する必要はありませんが、メソッド内で使用する必要がある「マジック ナンバー」ごとに多くの getValue() メソッドが必要です。

これを解決する別の「よりエレガントな」方法はありますか?

4

3 に答える 3

1

実際に 2 つの特殊化で異なる​​値を使用する必要があると仮定すると (たとえば、0.5 と 0.5f では必要ありません)、入力する必要が大幅に少なくなります。

template <typename T>
class SomeClass
{
  public:
    T doSomething(T x);

  private:
    static const T magic_number_1;
};

template <typename T>
T SomeClass<T>::doSomething(T x)
{
  T y = magic_number_1;
  /* 
   * Do computations...
  */
  return x;
}

template <>
const float SomeClass<float>::magic_number_1 = 0.5f;

template <>
const double SomeClass<double>::magic_number_1 = 0.5;
于 2012-06-18T17:53:18.593 に答える
1

回答とコメントをありがとうございました。これまでに述べたことの要約を作成し、結論を追加することを許可しました。

float または double 型で使用するためにインスタンス化される数学クラス テンプレートを実装します。クラスの内部でいくつかの数値リテラルを使用する必要があります。それらは、0.0、0.5、1.0、piなど、一般的に使用される数値リテラルと定数になります。クラスのインスタンス化をそのタイプに応じて異なるリテラルで機能させるソリューションを探しています。

float および double リテラルを使用するかどうか。

float と double に別々のリテラルを使用するかどうかに関係なく、少し話が進みました。これは、質問で挙げた少し残念な例が原因である可能性があります。この例では、とにかくコンパイル時にリテラルが適切な型に変換されるため、害はありません。しかし一般的には、式でリテラルを使用する必要がある場合があります。次に例を示します。

float foo(float x)
{
    return x * 3.14;
}

これにより、コンパイラは x を double に変換し、計算を行ってから、結果を float に戻すように強制されます。このような動作の長所と短所:

長所:

  • 実際の計算は倍精度で行われるため、精度が向上します。

短所:

  • パフォーマンスが問題になる場合、環境やプラットフォームによっては、実行が速くなったり遅くなったりする可能性があります。これにより、実装に応じてパフォーマンスがいくらか変化しますが、これは私が考える限りでは悪いことです。
  • リテラルの使用に応じて、一部の操作が float で実行され、一部の操作が double で実行されるため、計算の不整合が発生します。これにより、いくつかのバグが公開される可能性もあります。
  • とにかく内部計算が double で行われるため、最初に float のクラスを特殊化するという考えが壊れます。

結論として、目標は、クラスのインスタンス化を追加の変換なしで適切な型で機能させることです。0.5 などの double 型リテラルをあらゆる場所で使用し、コンパイラへの適切な変換の処理を残すという考えは、オプションではありません。

主題の詳細:通常、より単純な double リテラルの代わりに、float に float リテラルを使用する必要がありますか?

可能な解決策?

  • リテラルを使用する必要があるテンプレートのインスタンス化タイプごとにメソッドを特殊化します。リテラルに小さな変更を加えて同じコードを 2 回記述する必要があるため、これはおそらく最悪の解決策です。
  • 特殊getValue<type>()なメソッドを作成するか、Jonathan Wakely が投稿したように- 特殊なメンバー。これにより、クラスにばかげた名前のメンバーまたはメソッドが含まれる可能性がありgetZeroPointFive<float>()ます。
  • Mohammad と Tony Delroy は、すべてのリテラルを でラップするとうまくいくと指摘しました static_cast<T>()。適切な型への変換はコンパイル時に行われます。
于 2012-06-19T18:40:42.043 に答える
0

これについて心配する必要はありません。0.5 を使用すると、型が float の場合でも、コンパイラは 0.5f を使用した場合と同じ値に最適に初期化します。

少し長文ですが、私の回答の「ポリモーフィズムをサポートするその他のメカニズム」の部分を読みたいと思うかもしれません: Polymorphism in c++

関数全体での float 定数のより一般的な使用法 (特に比較と式) については、以下の bluemess のリンクを読む価値があります....

于 2012-06-18T17:51:36.113 に答える