float の配列と double の配列をポリモーフィックに変換できるクラスを作成したいと考えています。つまり、関連するインスタンス ( or によってパラメーター化された<double>
)<float>
と、 or を渡すfloat*
かどうかのdouble*
決定は、静的ではなく実行時に決定されます。
別の質問に対する提案された回答ですが、この回答に従って変更されています(クラス内でメンバー関数テンプレートを完全に特殊化することはできないことを理解しているため)、BaseDest
単純なオーバーロードされたメンバー関数を提供する純粋な仮想基本クラスをサブクラス化して定義しますDestImpl<T>
. DestImpl<T>
この基本クラスを使用して、インスタンスの動的コレクションをさまざまな .xml で維持しますT
。このクラスは、assign()
メンバー関数の明示的なオーバーロードを提供します。1 つは 用、double *
もう1 つは 用float *
です。実行時にBaseDest::assign()
がポリモーフィック ポインタまたは参照を介して呼び出され、これが で正しい仮想assign()
メンバ関数を呼び出すという考え方ですDestImpl<T>
。
ここで、配列の非ポインター型が T inDestImpl<T>
と一致すること、fast_copy()
関数が呼び出されること (おそらく memcpy) が重要であり、型が一致しない場合は、アイテムごとに静的にキャストされる低速のコピーが使用されます。行った。したがって、assign()
メンバー関数はこれをテンプレート化されたfunctorにオフロードします。このファンクターには 2 つの特殊化があります。1 つはファンクターの型パラメーターが の型と一致するDestImpl<T>
(したがって高速コピーを呼び出す) もので、もう 1 つは他のすべてのケースをキャッチする (そして低速コピーを呼び出す) フォールバックです。
ただし、次のコードをコンパイルできません。コメントは、コンパイラのエラーと警告が表示される場所を示しています-それらは関連していると思われます。私が理解していないのは、 の 2 番目の特殊apply_helper
化が としてインスタンス化できない理由apply_helper<double>
です。
class BaseDest {
public:
virtual ~BaseDest() {}
virtual void assign(const double * v, size_t cnt) = 0;
virtual void assign(const float * v, size_t cnt) = 0;
};
template <typename T>
class DestImpl : public BaseDest {
public:
void assign(const double * v, size_t cnt) {
assign_helper<T>()(v, cnt);
}
void assign(const float * v, size_t cnt) {
assign_helper<T>()(v, cnt); // ERROR: no matching function for call to object of type 'assign_helper<double>'
}
protected:
template <typename U>
struct assign_helper {
void operator()(const U * v, size_t cnt) {
for (size_t i = 0; i < cnt; ++i) {
//slow_copy(v[i]);
}
}
};
template <typename U>
struct assign_helper<T> { // WARNING: Class template partial specialization contains a template parameter that can not be deduced; this partial specialization will never be used
void operator()(const T * v, size_t cnt) {
//fast_copy(v, cnt);
}
};
};
void test() {
DestImpl<double> d; // error mentioned above appears when this is present
}
編集:これは機能しているように見えるものです-assign_helper
構造体(現在はクラス)をDestImpl<T>
クラス定義から移動します。これが正しい方法かどうかはわかりませんが、これまでのところうまくいくようです:
// slow copy between different types
template <typename T, typename U>
class assign_helper {
public:
void operator()(const U *v, size_t cnt) {
// slow copy
}
};
// fast copy between same types
template <typename T>
class assign_helper<T, T> {
public:
void operator()(const T * v, size_t cnt) {
// fast copy
}
};
class BaseDest {
public:
virtual ~BaseDest() {}
virtual void assign(const double * v, size_t cnt) = 0;
virtual void assign(const float * v, size_t cnt) = 0;
};
template <typename T>
class DestImpl : public BaseDest {
public:
virtual void assign(const double * v, size_t cnt) {
assign_helper<T, double>()(v, cnt);
}
virtual void assign(const float * v, size_t cnt) {
assign_helper<T, float>()(v, cnt);
}
};