Vector类的专用构造函数

时间:2015-11-24 17:18:23

标签: c++ templates math vectormath

我正在尝试编写一个数学矢量类。第一个版本如下:

  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),我很确定我需要一些构造函数来进行旋转,平移,缩放等。我假设我需要克服类似的问题。 / p>

如果你看到

我还在类外声明了运算符(+,*等),以及其他几个函数(点,十字等)。

但事情就是这样。对于长度为2,3,4的向量,我想要一个构造函数(或函数),它将x,y(对于Vec2),x,y,z或x,y,z,w作为参数。

但是,您似乎无法为此目的制作专门的构造函数。那个案子我该怎么办?我必须完全专注于三种情况吗?这不意味着我必须重写代码块吗?

我也有一个类似的Matrix类(Matrix),我很确定我需要一些构造函数来进行旋转,平移,缩放等。我假设我需要克服类似的问题。 / p>

如果您在代码中看到任何对您来说错误的内容,请随时指出。

编辑:如果我不够清楚,数组应该是一维的,并且它的所有组件都是相同的类型。专业化适用于具有2,3和4个元素的数组。

3 个答案:

答案 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);

答案 1 :(得分:0)

可变模板和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)
};

答案 2 :(得分:0)

您可以使用可变参数模板:

#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;
}