Полиморфизм по подтипам не является решением всех проблем.Я понимаю, что вы пытаетесь сделать, но я не совсем понимаю, почему решения по полиморфному шаблону недостаточно, и вам нужно иметь виртуальные операторы (которые вообще плохо сочетаются с полиморфизмом по подтипу).
Вы хотите иметь возможность определять операции над смешанными типами векторов, чтобы можно было вычислять результаты между реальными контейнерами и прокси-серверами для контейнеров.
Для этого прежде всего необходимо иметь базовый конечный тип, который вынужно, чтобы прокси для столбца матрицы был не реальным контейнером, а скорее видом контейнера, поэтому добавление двух из них должно вернуть реальный контейнер (например, контейнер, поддерживаемый фактическим std::array
?).
Подобным дизайном может управлять что-то вроде
template<typename ContainerType, typename ElementType>
class vector_of : public ContainerType
{
public:
vector_of(const ContainerType& container) : ContainerType(container) { }
vector_of<ContainerType, ElementType> operator+(const ElementType& a) const
{
vector_of<ContainerType, ElementType> copy = vector_of<ContainerType,ElementType>(*this);
std::for_each(copy.begin(), copy.end(), [&a](ElementType& element) { element += a; });
}
template<typename T>
vector_of<ContainerType, ElementType> operator+(const vector_of<T, ElementType>& a) const
{
vector_of<ContainerType, ElementType> copy(*this);
auto it = copy.begin();
auto it2 = a.begin();
while (it != copy.end() && it2 != a.end())
{
*it += *it2;
++it;
++it2;
}
return copy;
}
};
Хитрость здесь в том, что operator + - это метод шаблона, который принимает общий контейнер из элементов ElementType
.Код предполагает, что такого рода контейнеры предоставляют методы begin
и end
, которые возвращают итератор (который в любом случае является разумным выбором, поскольку он хорошо работает с STL).
С помощью вы можете делать вещинапример:
class MatrixRowProxy
{
private:
int* data;
size_t length;
public:
MatrixRowProxy(int* data, size_t length) : data(data), length(length) { }
int* begin() const { return data; }
int* end() const { return data + length; }
};
vector_of<std::array<int, 5>, int> base = vector_of<std::array<int, 5>, int>({ 1, 2, 3, 4, 5 });
vector_of<std::vector<int>, int> element = vector_of<std::vector<int>, int>({ 2, 3, 4, 5, 6 });
int* data = new int[5] { 10, 20, 30, 40, 50};
vector_of<MatrixRowProxy, int> proxy = vector_of<MatrixRowProxy, int>(MatrixRowProxy(data, 5));
auto result = base + element + proxy;
for (const auto& t : result)
std::cout << t << std::endl;
Таким образом, вы можете добавлять гетерогенные виды векторов без использования какого-либо метода virtual
.
Конечно, эти методы требуют создания нового результирующего объекта в методах.Это делается путем копирования этого в новый vector_of<ContainerType, ElementType>
.Ничто не мешает вам добавить третий аргумент шаблона, такой как VectorFactory, который позаботится об этом, чтобы вы могли использовать векторы, которые являются только обертками, также в LHS таких операторов.