私はすでに、自分がやろうとしていることに関連する2つの 質問をしました(1つは解決し、もう1つはまもなく終了します)。C ++テンプレートのインスタンス化では暗黙的な変換が許可されないことは知っていますが(たとえば、このコメントを参照)、それをシミュレートしたいと思います。
次のスケルトンコードがあるとします。
template <class T>
struct Base_A{
virtual void interface_func() const = 0;
};
template <class T>
struct Derived_A : public Base_A<T>{
typedef T value_type;
void interface_func() const{}
};
template <class T>
struct Base_B{
virtual void interface_func() = 0; // note: non-const
};
template <class T>
struct Derived_B : public Base_B<T>{
typedef T value_type;
void interface_func(){}
};
template <class BType>
struct Adapter : public Base_A<typename BType::value_type>{
BType &ref_B;
Adapter(BType &inst_B):ref_B(B_inst){}
void interface_func() const{} // does stuff with ref_B to simulate an A
};
template <class Should_Always_Be_Base_A>
void f(const Should_Always_Be_Base_A &arg){
// Only Base_A can be passed in by const ref
// Passing in a Base_B by const ref would not work.
}
Derived_A<int> A;
Derived_B<int> B;
f(A); // passes in A by const ref
f(B); // I want to pass in Adapter<Derived_B<int> >(B)
関数のテンプレートパラメータf
を常にBase_A
またはの派生クラスにしたいAdapter
。のタイプを制限するための答えはarg
実行できますが、アダプタへの暗黙の変換は実行できません。これを行う方法はありますか?f
最終的な結果は、f(A)
またはを呼び出すことができるようにしたいということですf(B)
。どちらの場合も、AまたはBの実際の派生型を知る必要がありますf
(f
基本クラスへの参照だけを見ることができません)。
脇:
現在、f(A)
作業中です。f(B)
実際には、アダプターの構築を実行するオーバーロードを呼び出しますが、N個の引数を取り、それぞれがAまたはBになる可能性がある他の関数があるため、2^N個のオーバーロードが必要になります。
不思議なことに、これは私が取り組んでいるマトリックスライブラリに適用されています。Base_A
基本マトリックスタイプをBase_B
表し、基本マトリックスビュータイプを表します。行列の引数を変更する操作の場合、非const参照によって行列を渡すか、const-refによって変更可能な行列ビューを渡す必要があります。アダプターは、単純なマトリックスからビューへのアダプターです。たとえば、私は現在、次のような機能を持っています
Scale(const MatrixViewBase<T> &Mview, const T &scale_factor){
// does the actual work
}
Scale(MatrixBase<T> &M, const T &scale_factor){
Scale(Adapter<MatrixBase<T> >(M), scale_factor);
}
ビューと非ビューの両方を処理するために必要なオーバーロードを作成するためだけに、これらすべての関数の2^Nコピーを作成するのは面倒でエラーが発生しやすくなります。現状では、Mviewに依存する型のインスタンスを生成する可能性があるため、Scaleが基本クラスだけでなくMviewの完全な派生型を認識できるようにしたいので、これでは十分ではありません。
編集1:すべてのBタイプを非constインターフェース機能を持つように変更しました。これが本来の意図でしたので、ご迷惑をおかけしましたことをお詫び申し上げます。
編集2:この動作するコードを持っていて、それでも2 ^ Nのオーバーロードが必要ですが、誰かがそれに対処する方法を提案しない限り、私はそれで生きることができます。
#include <iostream>
template <class T>
struct ReadableMatrix{
typedef T value_type;
};
template <class T>
struct WritableMatrix{
typedef T value_type;
};
template <class T>
struct WritableMatrixView{
typedef T value_type;
};
template <class T>
struct Matrix : public WritableMatrix<T>{
typedef T value_type;
typedef ReadableMatrix<T> readable_matrix;
typedef WritableMatrix<T> writable_matrix;
};
template <class T>
struct MatrixView : public WritableMatrixView<T>{
typedef T value_type;
typedef ReadableMatrix<T> readable_matrix; // not really used; needs an adapter before using
typedef WritableMatrixView<T> writable_matrix;
};
template <class T, class R>
struct IsReadableMatrix{
};
template <class T, class R>
struct IsReadableMatrix<ReadableMatrix<T>, R>{
typedef R type;
};
template <class T, class R>
struct IsWritableMatrix{
};
template <class T, class R>
struct IsWritableMatrix<WritableMatrix<T>, R>{
typedef R type;
};
template <class T, class R>
struct IsWritableMatrixView{
};
template <class T, class R>
struct IsWritableMatrixView<WritableMatrixView<T>, R>{
typedef R type;
};
template <class TA, class TB>
typename IsReadableMatrix<typename TA::readable_matrix,
typename IsWritableMatrixView<typename TB::writable_matrix,
void
>::type>::type
Copy(const TA &A, const TB &B){
std::cout << "Here" << std::endl;
}
template <class TA, class TB>
typename IsReadableMatrix<typename TA::readable_matrix,
typename IsWritableMatrix<typename TB::writable_matrix,
void
>::type>::type
Copy(const TA &A, TB &B){
std::cout << "Here2" << std::endl;
}
int main(){
Matrix<int> M, M2;
MatrixView<int> V, V2;
Copy(M, M2);
Copy(V, V2);
Copy(M, V);
Copy(V, M);
}