Я уже задавал два вопроса , связанных с тем, что я пытаюсь сделать (один решен, один из которых я скоро закрою). Я знаю, что создание экземпляра шаблона 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-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);
}