2

これは、一般的な数学関数を作成することを含む、非常に単純なテンプレートの問題です (C++ の専門家にとっては単純だと思います)。次のような単純なイプシロン関数があります。

template<class T>
static T Epsilon()
{
    return std::numeric_limits<T>::Min();
}

次のように、変数に割り当てたいと思います。

float epsilon = Math::Epsilon();

残念ながら、コンパイル エラーが発生します。

エラー C2783: 'T Math::Epsilon(void)': 'T' のテンプレート引数を推定できませんでした

エラーなしで、次のように割り当てることができます。

float epsilon = Math::Epsilon<float>();

テンプレート エンジンは私の T が "float" であることを認識できると思っていましたが、どうやらできないようです。ここで何が理解できなかったのですか?

4

5 に答える 5

9

問題は、C++ が完全な Hindley-Milner 演繹アルゴリズムを備えていないことです。代わりに、関数の引数からテンプレートの引数を推測します。

関数には引数がないため、テンプレート パラメーターを推測できません。

于 2013-10-17T11:17:34.230 に答える
4

テンプレートの引数推定は、戻り値の型ではなく、関数の引数に対してのみ機能します。これは、戻り値の型で関数をオーバーロードできないという点で似ています (戻り値を使用できないという単純な理由で、その場合、コンパイラは適切な関数を推測できませんでした)。

于 2013-10-17T11:17:42.260 に答える
4

一般に、関数テンプレートのパラメーターは、引数の型に基づいてのみ推測されます。議論も推論もありません。これを回避するには、コンパイラに変換を推測させる必要があります。たとえば、次のようなものです。

struct Epsilon
{
    template <typename T>
    operator T() const
    {
        return std::numeric_limits<T>::min();
    }
};

この場合、Epsilon実際には への呼び出しによってオブジェクトが作成されます。このオブジェクトは、ターゲットの型に暗黙的に変換できます。推論は、コンパイラが「関数」を呼び出そうとするときではなく、変換を探すときに行われます。

于 2013-10-17T12:00:27.877 に答える
1

そうすることはお勧めしませんが、返された値イプシロンから型を推測する必要がある場合は、次のようにすることができます。

float epsilon{};
epsilon = Math::Epsilon<decltype(epsilon)>();

戻り値の型は推測できます。冗長性を避けて単一floatの を使用する場合は、次のこともできます。

auto e = Epsilon<float>();
于 2017-01-13T00:26:35.017 に答える
0

あなたのアプローチには根本的な問題があります。

戻り値は関数シグネチャの一部ではありません。つまり、その戻り値を持つ関数は 1 つしか存在できません。

理解するには、コンパイルしてみてください

float epsilon = Math::Epsilon<float>();
int epsilon = Math::Epsilon<int>();

関数は同じ署名を持つため、機能しません。

std::numeric_limits動作するテンプレートを作成するには、C++11 を参照してください。ただし、テンプレート引数は、最初に評価してから割り当てる必要があるため、推測できません。

于 2013-10-17T11:19:12.280 に答える