4

自分のスニペットライブラリとテンプレートクラスの練習の両方のために、ユニバーサルベクトルクラスを作成しようとしています。基本的に、Vectorクラスは、精度がfloat、double、longdoubleなどのいずれであるかを選択できるようにテンプレート化されています。

私が遭遇した問題は、ベクトルをスケーリングする目的で*演算子をオーバーロードすることです。すべての作業オーバーロードとメンバー関数を除外すると、クラス定義は次のようになります。

#pragma once

#include <math.h>   //  for sqrt function when normalizing

template <typename T> class Vector;
template <typename T> Vector<T> operator*(const Vector<T>& obj);

template <typename T> class Vector {
private:
    //  Attributes:
    static const int DIMS = 3;
    T component[DIMS];

public:
    enum { 
        X, Y, Z
    };

public:
    //  Constructors:
    Vector(void) {
        for (int i=0; i<DIMS; ++i) {
            component[i] = T();
        }
    }
    Vector(T x, T y, T z) {
        component[X] = x;
        component[Y] = y;
        component[Z] = z;
    }

    //  Destructor:
    ~Vector(void) { }

    //  Scaling:
    friend Vector<T> operator*(const Vector<T>& obj);
    Vector operator*(const T scale) {
        Vector<T> result = Vector<T>();

        for (int i=0; i<DIMS; ++i) {
            result.component[i] = component[i] * scale;
        }

        return result;
    }
};

template <typename T>
Vector<T> operator*(const Vector<T>& obj) {
    Vector<T> result = Vector<T>();

    for (int i=0; i<DIMS; ++i) {
        result.component[i] = obj.component[i] * this*;
    }

    return result;
}

私のメインメソッドには、次のコード行があります。

Vector<float> testVector1 = Vector<float>(1.0f, 0.0f, 0.0f);
Vector<float> testVector2 = Vector<float>(0.0f, 1.0f, 0.0f);
Vector<float> testVector3 = 10.0f * testVector1;
Vector<float> testVector4 = testVector2 * 10.0f;

1つのエラーを除いてすべてが正常にコンパイルされます。main()の4行目は正常に機能しますが(ベクトルにスカラーを乗算)、3行目(スカラーをベクトルに乗算)はエラーになります。

Error 1 error C2677: binary '*' : no global operator found which takes type 'Vector<T>' (or there is no acceptable conversion)

この問題についての私の最も良い推測は、コンパイラがオーバーロードしようとしているプリミティブの*演算子を認識しておらず、テンプレートに渡されるまでクラスが型を認識しないため、直接伝えることができないということです。私がやろうとしていることを達成する方法はありますか、またはテンプレートは演算子のオーバーロードのために常にクラスに従う必要がありますか?

更新: jwismarなどのおかげで、左利きのオーバーロードでの悪い試みを見つけました。クラス内の関数の定義は次のとおりです。

friend Vector<T> operator*(T scalar, const Vector<T>& obj);

そして、その実装は次のとおりです。

template <typename T> 
Vector<T> operator*(T scalar, const Vector<T>& obj) {
    Vector<T> result = Vector<T>();

    for (int i=0; i<DIMS; ++i) {
        result.component[i] = obj.component[i] * scalar;
    }

    return result;
}

クラスの上のオーバーロードの最初の宣言は現在template <typename T> Vector<T> operator*(T scalar, const Vector<T>& obj);ですが、コメントアウトされているかどうかに関係なく、同じエラーが発生します。

次に、テンプレートと演算子のオーバーロードに関するより具体的な質問に移ります。エラーは未解決の外部ですが、コンパイラはコンパイル時に失敗します。

Error 1 error LNK2019: unresolved external symbol "class Vector<float> __cdecl operator*(float,class Vector<float> const &)" (??D@YA?AV?$Vector@M@@MABV0@@Z) referenced in function _main C:\Users\D03457489\Desktop\UVCTester\UVCTester\main.obj UVCTester

operator*(float, Vector<float>)したがって、コンパイラは、の定義を見つけることはできても、実装を見つけることができないと言っています。したがって、新しい質問は次のとおりです。私の側での別の基本的な監視の結果ですか、それともこの方法でテンプレートを使用して、オペランドの左側が不明な演算子のオーバーロードを生成することはできませんか?

4

4 に答える 4

1

エラーが発生しているのは4行目ではなく、3行目です。コンパイラは左側にフロートをとるビルトインを探していますが、見つかりません。次のような無料の関数を定義する必要があります。

template <typename T> Vector<T> operator*(T scalar, const Vector<T>& obj);
于 2012-08-01T23:36:56.783 に答える
1

operator*二項演算子であるため、2つの引数が必要です。つまり、左側に適用されて引数を取るメンバー関数(右側)として、または2つの引数を取る自由関数として実装できます。通常は、無料の関数として実装することをお勧めします。double*Vector<T>左側はクラスではないので、実装できるようにしたい場合はさらにそうです。そのオーバーロードのシグネチャは次のようになります。

template <typename T>
Vector<T> operator*( T d, Vector<T> v );

追加する可能性のあるもの:

template <typename T>
Vector<T> operator*( Vector<T> v, T d );
于 2012-08-02T01:44:52.150 に答える
0

代わりに、この関数シグネチャを試してください(テストされていません)。

template <typename T, typename F>
Vector<T> operator*(const F &lhs, const Vector<T>& rhs);

次のようなステートメントを許可する必要があります。

auto vec = f * other_vec;

F種類の定義された演算子を持つすべてのタイプの場合:

template <typename F, typename T>
undetermined operator*(const F& lhs, const T &rhs);

ここで、Tはに使用される型Vector<T>であり、返される型は暗黙的ににキャストできTます。

したがって、おそらく次のように機能します。

long l;
float f;
int i;
//.......

Vector<float> v1;
v2 = l * v1;
v3 = f * v2;
v4 = i * v3;
于 2012-08-01T23:37:45.770 に答える
0

のLHSでスカラーを許可する関数を定義する必要があります*。幸い、これは比較的簡単に実装できます。

template <typename T>
Vector<T> operator*(const T scale, const Vector<T> &v) {
    Vector<T> result = v;
    return result * scale;
}

2つの間でコンポーネントごとの乗算を行った他の関数Vectorが不適切に宣言され、実装されました。友達である必要はありません:

/*friend*/ Vector<T> operator*(const Vector<T>& obj);

そして、それをクラスのメソッドとして実装します。

template <typename T>
Vector<T> Vector<T>::operator*(const Vector<T>& obj) {
    Vector<T> result = Vector<T>();

    for (int i=0; i<DIMS; ++i) {
        result.component[i] = obj.component[i] * component[i];
    }

    return result;
}
于 2012-08-02T00:31:41.900 に答える