Унаследованное добавление присваивания op. Как мне вернуть правильный тип?

У меня есть этот класс для факторизации общих операций на N-мерных векторных пространствах:

template <unsigned int N>
struct BaseVector
{
float m_data[N];
// Common operations like dot product, magnitude, test for unity, etc.
};

Примечание: я действительно хочу разложить как можно больше кода, чтобы минимизировать объем документации и тестирования.

Теперь я извлекаю два класса:

// 3D geometric vectors
struct Vector3 : public BaseVector<3>
{
Vector3 Cross(const Vector3& other);
// ...
};

// Quaternions are a particular kind of vector space
struct Quaternion : public BaseVector<4>
{
void Interpolate(const Quaternion& start, const Quaternion& end, ...);
// ...
};

Эти классы ведут себя одинаково для сложения и скалярного умножения (компонентная операция); Итак, я хочу факторизовать operator+=() а также operator*=() в базовом классе векторов.

Мой вопрос: как я могу вернуть ссылку правильного типа?

template <unsigned int N>
struct BaseVector
{
??? & operator+=(const BaseVector& other)
{
transform(m_data, m_data+N, other.m_data, m_data, plus<float>());
return ???
}
};

Все мои идеи (перечисленные ниже) не удовлетворяют, и я был бы признателен за некоторые предложения, спасибо!


Идея № 1: использовать C ++ ковариантный механизм возвращаемого типа. Но тогда я должен перегрузить эти операторы в производных классах — я прав? (Что для меня означает повторное тестирование.)

Идея № 2: перейти на шаблоны?

template <unsigned int N>
struct BaseVector
{
template <typename T2>
T2 & operator+=(const T2& other)
{
transform(...);
return *this; // THIS IS WRONG! I'm trying to "upcast"}
};

Идея № 3: Факторизовать код в закрытый член в базовом векторе, но затем мне нужно добавить больше функций в производные классы (и больше материала для тестирования)

template <unsigned int N>
struct BaseVector
{
private:
void DoOperatorPlus(const BaseVector& other) { transform(...); }
};

struct Vector4 : public BaseVector<4>
{
Vector4& operator+=(const Vector4& other)
{
DoOperatorPlus(other);
return *this;
}
};

1

Решение

Вы могли бы на самом деле попытаться использовать CRTP

Идея состоит в том, что вы передаете параметр шаблона вашему базовому классу вашего производного класса:

    template <unsigned int N, typename Derived>
struct BaseVector
{
Derived & operator+=(const Derived& other)
{
transform(m_data, m_data+N, other.m_data, m_data, plus<float>());
return static_cast<Derived&>(*this);
}
};

Я не уверен на 100% насчет возврата, но это должно дать вам представление.

3

Другие решения

Других решений пока нет …