Специализированный конструктор для класса Vector

Я пытаюсь написать математический векторный класс. Первая версия выглядит так:

  template <typename T, unsigned int n>
struct Vector {
Vector<T, n>(T t = T()) // default
{
for (int i = 0; i < n; i++)
{
data[i] = t;
}
}

Vector<T, n>(const Vector<T, n> &aVector)
{
for (unsigned int i = 0; i < n; i++)
{
data[i] = aVector.data[i];
}
}

Vector<T, n>(const T arr[n])
{
for (unsigned int i = 0; i < n; i++)
{
data[i] = arr[i];
}
}

T& operator[](unsigned int i);
const T& operator[](unsigned int i) const;
Vector<T, n>& operator=(const Vector<T, n> &aVector);

void normalise();

T data[n];
};

У меня также есть операторы (+, * и т. Д.), Объявленные вне класса, а также пара других классов.

Вот вещь, хотя. Для векторов длины 2, 3, 4 я хотел бы иметь конструктор (или функцию), который принимает x, y (для Vec2), x, y, z или x, y, z, w в качестве параметров.

Однако, кажется, что вы не можете создавать специализированные конструкторы для этой цели. Как мне поступить в этом случае? Должен ли я полностью специализировать три случая? Разве это не означает, что я должен переписать куски кода?

У меня также есть аналогичный класс Matrix (Matrix), и я почти уверен, что мне понадобятся некоторые конструкторы для вращения, перемещения, масштабирования и т. Д. Я предполагаю, что мне нужно будет преодолеть аналогичную проблему.

Если ты видишь

У меня также есть операторы (+, * и т. Д.), Объявленные вне класса, а также пара других функций (точка, крестик и т. Д.).

Вот вещь, хотя. Для векторов длины 2, 3, 4 я хотел бы иметь конструктор (или функцию), который принимает x, y (для Vec2), x, y, z или x, y, z, w в качестве параметров.

Однако, кажется, что вы не можете создавать специализированные конструкторы для этой цели. Как мне поступить в этом случае? Должен ли я полностью специализировать три случая? Разве это не означает, что я должен переписать куски кода?

У меня также есть аналогичный класс Matrix (Matrix), и я почти уверен, что мне понадобятся некоторые конструкторы для вращения, перемещения, масштабирования и т. Д. Я предполагаю, что мне нужно будет преодолеть аналогичную проблему.

Если вы видите в коде что-то, что кажется вам неправильным, не стесняйтесь указывать на это, кстати.

РЕДАКТИРОВАТЬ: В случае, если я не был достаточно ясен, массивы должны быть одномерными, и все его компоненты одного типа. Специализации для массивов с 2, 3 и 4 элементами.

0

Решение

Вы можете использовать шаблон variadic:

#include <chrono>
#include <future>
#include <iostream>
#include <stdexcept>template<typename T, unsigned int n>
struct Vector
{
// Note: We need x and y:
// The default (in the question) is a constructor taking a single argument.
template <typename ... Args>
Vector(T x, T y, Args ... args)
{
static_assert(sizeof ... (Args) == n - 2, "Invalid number of arguments");
auto initializer_list = { x, y, std::forward<Args>(args)... };
std::copy(initializer_list.begin(), initializer_list.end(), data);

}

T data[n];
};template<typename T, unsigned int n>
void print(const Vector<T, n>& v) {
for(unsigned i = 0; i < n; ++i)
std::cout << v.data[i] << ' ';
std::cout << '\n';
}int main()
{
Vector<int, 2> v2(1, 2);
Vector<int, 3> v3(1, 2, 3);
Vector<int, 4> v4(1, 2, 3, 4);
print(v2);
print(v3);
print(v4);

// Invalid number of arguments
// Vector<int, 3> e2(1, 2);

// Invalid number of arguments
// Vector<int, 3> e4(1, 2, 3, 4);
return 0;
}
0

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

Лично я бы объявил разные классы для каждого вектора. Vec2<T1, T2>, Vec3<T1, T2, T3>, а также Vec4<T1, T2, T3, T4>, Сделать каждый Vec* класс публично наследовать не шаблонный базовый класс Vector, а затем сделать статическую функцию create в Vector с перегрузкой для каждого Vec* тип, который будет отвечать за их создание. Псевдо-пример для Vec3:

template<T1, T2, T3> static std::shared_ptr<Vector> create(T1 a1, T2 a2, T3 a3)
{
return new Vec3<T1, T2, T3>(a1, a2, a3);
}
auto vec = Vector::create<int, int, int>(1, 2, 3);
0

шаблон variadic и SFINAE могут решить это.
но я думаю, что проще было бы унаследовать от (специализированного) помощника

template <typename T, unsigned int n>
struct VectorHelper<T, n>
{
T data[n];
};

template <typename T>
struct VectorHelper<T, 2>
{
VectorHelper(T x, T y) : {data[0] = x; data[1] = y;}
T data[2];
};

template <typename T>
struct VectorHelper<T, 3>
{
VectorHelper(T x, T y, T z) : {data[0] = x; data[1] = y; data[2] = z}
T data[3];
};template <typename T, unsigned int n>
struct Vector : private VectorHelper<T, n>
{
using VectorHelper<T, n>::VectorHelper; // use base constructor(s)
// your previous implementation without `data` (as member of base)
};
0
По вопросам рекламы [email protected]