3

テンプレート マトリックス クラスを作成していますが、* 演算子のオーバーロードがどのように機能するかについて少し混乱しています。

このようなものをオーバーロードしたいと思います(無関係なコードを省略しています):

template<typename T>class Matrix4t
{

friend vector3 operator*(const vector3 &inputV3, const matrix4t &inputM4t);

template <typename scalarT>
friend scalarT operator*(const scalarT &inputSclT, const matrix4t &inputM4t);

public:
const matrix4t operator*(const matrix4t)

vector3 operator*(const vector3 &inputV3);

template <typename scalarT>
const matrix4t operator*(const scalarT&);

}

個々の乗算の定義が正しいと仮定すると、これにより、オペランドの両側から vector3 型のオブジェクトを使用して行列オブジェクトを乗算し、毎回 vector3 を返すことができるはずです。また、float、double などのスカラー テンプレート値を使用して行列を乗算できるようにする必要があります。これらのメソッドの定義は、ベクトルとスカラーの乗算を可能にするために異なる必要があるため、両方のテンプレートを使用するだけではありません。

ただし、vector3 でこの演算子を使用すると、コンパイラは明示的に宣言された vector3 メソッドを使用することを認識しますか、またはメソッドのテンプレート化されたバージョンを作成しようとしますが、定義はスカラー値のみを許可するように記述されているため、機能しません。 、そしておそらくメソッドの再定義についても文句を言います。

これが機能するかどうか、または他にどうすればよいかについて何か考えはありますか?

乾杯

4

1 に答える 1

4

必要以上に複雑なソリューションを目指しているのではないかと感じているので、最初から構築を開始し、詳細は後で説明します。まず、提案された構文とその意味の分析を開始します。

friend vector3 operator*(const vector3 &v, const matrix4t &m);
template <typename scalarT>
friend scalarT operator*(const scalarT &inputSclT, const matrix4t &inputM4t);

これらは友達宣言です。Friend 宣言は、クラスの外部にエンティティを宣言し(存在することをコンパイラに伝えます)、そのようなエンティティには、このクラスの内部 (この場合はテンプレート) へのフル アクセスを許可する必要があります。2 番目のフレンド宣言は、const 参照によって型とオブジェクトの両方operator*を取り、値を生成するフリー関数テンプレートです。このフレンド宣言は奇妙に思えます。スカラー値による行列の乗算は、通常、単なるスカラー値ではなく、同じ次元の別の行列を生成します。scalarTmatrix4T<T>scalarT

クラス テンプレート内では、テンプレートの名前はテンプレートmatrix4tを参照するのではなく、特定の特殊化を参照することに注意してください (つまりmatrix4t<T>、テンプレートの名前ではなく、 を表します)。この区別は今は重要ではないように思えるかもしれませんが、遅かれ早かれその重要性に気付くでしょう。

2 番目の宣言は、 const 参照によってaと a の両方operator*を受け取り、別の を生成するテンプレート化されていないフリー関数です。の定義内にあるため、テンプレートの名前は特殊化を参照しますが、テンプレートのみを参照し、特定のインスタンス化は参照しません。特定の typeを受け入れるテンプレートにするか、単一の型 (テンプレートの引数にすることができます)を受け入れるテンプレート化されていない関数にする必要があります。他の宣言と同じように、戻り値がオフになる場合とオフになる場合があります...ベクトルの次元が何であるかに依存します(行または列ですか?)vector3matrix4tvector3matrix4tmatrix4t<T>vector3vector3<U>UTvector3<T>

実際の友達関係については、別の同様の質問に対するこの回答を読むことをお勧めします。

実際の演算子として、スカラー型の場合、次のアプローチをお勧めします。

  • operator*=格納されているのと同じ型のスカラーを引数として取る実装
  • の両方のバージョンを実装operator*するoperator*=

.

template <typename T> class matrix4t {
public:
    matrix4t& operator*=( T scalar ); // and implement
    friend matrix4t operator*( matrix4t lhs, T scalar ) {
       return lhs*=scalar;
    }
    friend matrix4t operator*( T scalar, matrix4t rhs ) {
       return rhs*=scalar;
    }
};

注:operator*=行列を左辺として一度実装します (行列を右辺としてオーバーロードを提供することもできますが、少し奇妙に見えます:5 *= matrix行列を生成します...)。に転送することにより、無料の関数として実装operator*します(友情は、インスタンス化する型ごとに無料の関数を提供するためにのみ使用されます。リンクされた回答を読んでください)operator*=

ベクトルで乗算する場合 (対称ではないため)、単一の実装にディスパッチするトリックは機能しませんが、上記のようにテンプレート化されていないフレンドとして 2 つの実装を提供できます。

混合タイプの操作を提供したい場合は、上記のすべてをテンプレートにする必要があります。追加された複雑さはテンプレートではなく、タイプをプロモートしたい場合に結果タイプがどうあるべきかを決定することです。C++11 では、最も簡単な方法は、decltype戻り値の型を使用して末尾に置くことです。

template <typename U>
friend auto operator*( matrixt4 lhs, U scalar ) -> matrix4t< decltype(scalar * element(0,0) ) > {
   // implement here
}

についても同様ですoperator*(scalar,matrix)。型をプロモートしている場合、operator*=(型が lhs と同じであるため) はまったく意味をなさない可能性があることに注意してください。それを行うことを検討する場合、 は参照によって引数operator+を取得しmatrix4t<A>(適切な型ではない可能性があるため)、matrix4t<B>戻り値の型にコピーする必要があります (ここでA、 とBはそれぞれ、乗算される行列と結果の型です)。

ここから先は、必要なものや実装したいものを決定する必要があり、より具体的な質問が寄せられたときに尋ねたいと思うかもしれません。

于 2012-08-08T03:39:04.447 に答える