Я хотел написать свой собственный шаблон класса Vector, а также хотел бы добавить некоторые специализации, например трехмерный векторный тип, к которому к компонентам можно получить доступ через x/y/z.C++ Уменьшение резервирования шаблонов для шаблонов
Шаблон и специализации работают до сих пор, но проблема в том, что для специализированных шаблонов требуется много копий/вставки из базового шаблона для работы. Я хотел бы уменьшить это.
Это то, что это выглядит как прямо сейчас:
template<class T, unsigned int dim>
class Vector;
template<class T, unsigned int dim>
Vector<T, dim> add(Vector<T, dim> const& lhs, Vector<T, dim> const& rhs)
{
Vector<T, dim> tmp;
for (unsigned int i = 0; i < dim; ++i)
{
tmp[i] = lhs[i] + rhs[i];
}
return tmp;
}
template<class T, unsigned int dim, class S>
Vector<T, dim> add(Vector<T, dim> const& lhs, S const& rhs)
{
Vector<T, dim> tmp;
for (unsigned int i = 0; i < dim; ++i)
{
tmp[i] = lhs[i] + rhs;
}
return tmp;
}
template<class T, unsigned int dim>
Vector<T, dim> operator+(Vector<T, dim> const& lhs, Vector<T, dim> const& rhs)
{
return vectors::add(lhs, rhs);
}
template<class T, unsigned int dim, class S>
Vector<T, dim> operator+(Vector<T, dim> const& lhs, S const& rhs)
{
return vectors::add(lhs, rhs);
}
template<class T, unsigned int dim>
class Vector
{
//...
protected:
T values[dim] __attribute((aligned(16)));
public:
template<class R, unsigned int fdim>
friend Vector<R, fdim> operator+(Vector<R, fdim> const& lhs, Vector<R, fdim> const& rhs);
template<class R, unsigned int fdim, class S>
friend Vector<R, fdim> operator+(Vector<R, fdim> const& lhs, S const& rhs);
template<class R, unsigned int fdim, class S>
friend Vector<R, fdim> operator+(S const& lhs, Vector<R, fdim> const& rhs);
//...
//constructors, etc.
};
template<class T>
class Vector<T, 3>
{
//...
protected:
T values[3] __attribute((aligned(16)));
public:
T& x = values[0];
T& y = values[1];
T& z = values[2];
//lots of copy-pasta :(
template<class R, unsigned int fdim>
friend Vector<R, fdim> operator+(Vector<R, fdim> const& lhs, Vector<R, fdim> const& rhs);
template<class R, unsigned int fdim, class S>
friend Vector<R, fdim> operator+(Vector<R, fdim> const& lhs, S const& rhs);
template<class R, unsigned int fdim, class S>
friend Vector<R, fdim> operator+(S const& lhs, Vector<R, fdim> const& rhs);
//...
//constructors, etc.
};
Теперь я думал, что простое решение было бы просто определить Vector3D
как суб-класс Vector
шаблона, например, так:
template<class T>
class Vector3D: public Vector<T, 3>
{
//...
public:
T& x = values[0];
T& y = values[1];
T& z = values[2];
//no copy-pasta :)
//...
//constructors, etc.
};
Это не работает вообще, из-за неопределенности:
ambiguous overload for ‘operator+’ (operand types are ‘const vec3f {aka const math::vectors::Vector3D<float>}’ and ‘math::vectors::vec3f {aka math::vectors::Vector3D<float>}’)
../main.cpp:84:16: note: candidates are:
In file included from ../main.cpp:10:0:
../include/vector.hpp:720:16: note: math::vectors::Vector<T, dim> math::vectors::operator+(const math::vectors::Vector<T, dim>&, const math::vectors::Vector<T, dim>&) [with T = float; unsigned int dim = 3u]
Vector<T, dim> operator+(Vector<T, dim> const& lhs, Vector<T, dim> const& rhs)
^
../include/vector.hpp:726:16: note: math::vectors::Vector<T, dim> math::vectors::operator+(const math::vectors::Vector<T, dim>&, const S&) [with T = float; unsigned int dim = 3u; S = math::vectors::Vector3D<float>]
Vector<T, dim> operator+(Vector<T, dim> const& lhs, S const& rhs)
^
../include/vector.hpp:732:16: note: math::vectors::Vector<T, dim> math::vectors::operator+(const S&, const math::vectors::Vector<T, dim>&) [with T = float; unsigned int dim = 3u; S = math::vectors::Vector3D<float>]
Vector<T, dim> operator+(S const& lhs, Vector<T, dim> const& rhs)
Таким образом, похоже, что замена шаблона не выполняется, потому что S также может быть заменен новым классом Vector3D, в то время как он должен обрабатывать только скаляры.
Так что я пытался избавиться от этого вопроса, написав небольшой класс-оболочку для скаляров так:
template<class T>
class ScalarType
{
public:
T value;
ScalarType() :
value(0)
{
}
ScalarType(T const& _v) :
value(_v)
{
}
ScalarType(ScalarType<T> const& rhs) :
value(rhs.value)
{
}
operator T&()
{
return value;
}
operator T() const
{
return value;
}
};
И заменить все экземпляры S const& (l|r)hs
с ScalarType<S> const& (l|r)hs
.
Это привело к тому, что операторы с векторами с обеих сторон снова работали, но операторы, которые должны обрабатывать операции Vector-Scalar, еще не сработали.
На этот раз это связано с тем, что скалярное значение должно быть явно типа ScalarType
, так как неявные преобразования к ним не работают с заменой шаблона.
Итак, есть ли способ заставить это работать вообще или мне нужно придерживаться кода копирования-вставки?
Вот возможная реализация http://stackoverflow.com/questions/31449433/ generic-c-многомерные-итераторы/38510047 # 38510047 – slavanap
Вы делаете слишком много. Имейте вектор базового класса (value tuple) и реализуйте операции с циклами (используя параметр шаблона «dim»). Тогда (только если производительность и (!) Компилятор, сгенерированный сборкой, недостаточно хороши), настройте специализированные шаблоны. В любом случае, сохраняйте специализированную функциональность в специализированных шаблонах (не загромождайте базовый класс) –
@ DieterLücking хорошо, это план. Операторы не специализируются вообще, просто сам векторный класс, и только потому, что я хочу, чтобы векторные компоненты были доступны через простые ссылки, такие как Vector3D test; test.x = 12; Но когда я просто специализируюсь на обычном способе, я должен либо переопределить каждую перегрузку оператора, либо использовать функции друзей, как указано выше. –