我已经问了两个 与我正在尝试做的事情相关的问题(一个已解决,一个我将很快关闭)。我知道 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
可以的,但是隐式转换为 Adapter 不行。有没有办法做到这一点?最终结果是我希望能够调用f
为f(A)
or f(B)
,并且在这两种情况下我都需要知道 A 或 B 的实际派生类型f
(f
不能只看到对基类的引用)。
在旁边:
目前,我刚刚开始f(A)
工作,f(B)
实际上调用了一个执行适配器构造的重载,但我还有其他接受 N 个参数的函数,每个参数可以是 A 或 B,所以我需要 2^N 个重载。
出于好奇,这适用于我正在研究的矩阵库。Base_A
表示基本矩阵类型,并Base_B
表示基本矩阵视图类型。对于将修改矩阵参数的操作,我需要通过非常量引用传递矩阵或通过 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 个副本只是为了创建处理视图和非视图所需的重载,既繁琐又容易出错。事实上,这还不够好,因为我希望 Scale 能够知道 Mview 的完整派生类型,而不仅仅是基类,因为我可能会生成依赖于 Mview 的类型的实例。
编辑 1:将所有 B 类型更改为具有非常量接口函数。这是最初的意图,因此对任何混淆表示歉意。
编辑 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);
}