gpt4 book ai didi

c++ - 用 C++ 编写广义 vector 类

转载 作者:搜寻专家 更新时间:2023-10-31 00:36:45 26 4
gpt4 key购买 nike

我正在尝试实现一个 Vector 类以用于我的图形项目。我想按长度和类型对 vector 进行模板化,并且我希望能够使用 A.x、A.y、A.z、A.w 来访问 vector A 的成员(例如)。

这是我的第一次尝试。我绝对不是 C++ 模板方面的专家!我试图用 Vec2、Vec3 和 Vec4 的专用版本实现一个通用 Vector 类。每个专门的类都有一个 union ,允许我使用它们的名称访问坐标。不幸的是,如果不为每个专用类重新实现每个 vector 函数,我无法弄清楚如何做到这一点。

请记住,我想实现一些仅适用于特定长度 vector 的函数。例如,叉积仅适用于 vec3,但点积(或运算符*)适用于所有长度的 vector 。

#include <cstdint>

using namespace std;

//*********************************************************************
// Vector implementation parameterized by type and size.
//*********************************************************************

template <typename T, size_t SIZE>
class Vector {

public:
T data[SIZE];
size_t size;

Vector(T* arr);
};

template <typename T, size_t SIZE> Vector<T, SIZE>::Vector(T* arr) {
size = SIZE;

for(int i=0; i<size; i++) {
data[i] = arr[i];
}

}

//*********************************************************************
// Vec2 is a specialization of Vector with length 2.
//*********************************************************************

typedef Vector<float, 2> Vec2f;
typedef Vector<int, 2> Vec2d;

template <typename T>
class Vector <T, 2> {

public:
union {
T data[2];
struct {
T x;
T y;
};
};

size_t size;

Vector(T x, T y);
};

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

//*********************************************************************
// Vec3 is a specialization of Vector with length 3.
//*********************************************************************

typedef Vector<float, 3> Vec3f;
typedef Vector<int, 3> Vec3d;

template <typename T>
class Vector <T, 3> {

public:
union {
T data[3];
struct {
T x;
T y;
T z;
};
};

size_t size;

Vector(T x, T y, T z);
};

template <typename T> Vector<T, 3>::Vector(T x, T y, T z) {
data[0] = x; data[1] = y; data[2] = z;
size = 3;
}

//*********************************************************************
// Vec4 is a specialization of Vector with length 4.
//*********************************************************************

typedef Vector<float, 4> Vec4f;
typedef Vector<int, 4> Vec4d;

template <typename T>
class Vector <T, 4> {

public:
union {
T data[4];
struct {
T x;
T y;
T z;
T w;
};
};

size_t size;

Vector(T x, T y, T z, T w);
};

template <typename T> Vector<T, 4>::Vector(T x, T y, T z, T w) {
data[0] = x; data[1] = y; data[2] = z; data[3] = w;
size = 4;
}

最佳答案

避免在多个特化中重复实现相同功能的通常解决方法是从公共(public)基类继承,并在基类中实现这些功能:

template <typename T>
struct VectorBase {
// common stuff
};

template <typename T, std::size_t N>
struct Vector : VectorBase<T> {
// ...
};

template <typename T>
struct Vector<T, 2> : VectorBase<T> {
// ...
};

template <typename T>
struct Vector<T, 3> : VectorBase<T> {
// ...
friend Vector<T, 3> cross(const Vector<T, 3>&, const Vector<T, 3>&);
};

您将遇到的下一个问题是需要从公共(public)基访问派生类中的成员(例如,获取 xsize() 的值) .您可以使用 Curiously Recurring Template Pattern (CRTP) 来做到这一点:

template <typename T, typename CRTP>
struct VectorBase {
CRTP& crtp() { return static_cast<CRTP&>(*this); }
const CRTP& crtp() const { return static_cast<const CRTP&>(*this); }

std::size_t size() const {
return std::extent<decltype(CRTP::data)>::value;
}

void zero() {
std::fill(std::begin(crtp().data), std::end(crtp().data), T());
}

using iterator = T*;
using const_iterator = const T*;
iterator begin() { return &crtp().data[0]; }
iterator end() { return &crtp().data[0] + size(); }
const_iterator begin() const { return &crtp().data[0]; }
const_iterator end() const { return &crtp().data[0] + size(); }

T& operator [] (std::size_t i) {
return crtp().data[i];
}
const T& operator [] (std::size_t i) const {
return crtp().data[i];
}
};

template <typename T, std::size_t N>
struct Vector : VectorBase<T, Vector<T, N>> {
union {
T data[N];
struct {
T x, y, z, w;
};
};
};

template <typename T>
struct Vector<T, 2> : VectorBase<T, Vector<T, 2>> {
union {
T data[2];
struct {
T x, y;
};
};
};

template <typename T>
struct Vector<T, 3> : VectorBase<T, Vector<T, 3>> {
union {
T data[3];
struct {
T x, y, z;
};
};
};

template <typename T, typename U, std::size_t N>
auto operator * (const Vector<T, N>& a, const Vector<U, N>& b)
-> Vector<decltype(a[0] * b[0]), N> {
Vector<decltype(a[0] * b[0]), N> result;
for (std::size_t i = 0; i < N; ++i) {
result[i] = a[i] * b[i];
}
return result;
}

template <typename T, typename U, std::size_t N>
auto dot(const Vector<T, N>& a, const Vector<U, N>& b)
-> decltype(a[0] * b[0]) {
auto product = a * b;
using V = decltype(product.x);
return std::accumulate(std::begin(product), std::end(product), V(0));
}

** Sample Code at Coliru **

评论者提到的未定义行为有两个问题:

  1. 匿名结构(例如,struct { T x, y, z; };)是 GNU 扩展,因此可能只适用于 GCC 和兼容的编译器 (clang) .

  2. 从最后存储的成员以外的 union 成员读取通常是未定义的行为;考虑到所涉及的每种类型都是标准布局并且读取/写入的所有值都属于同一类型,因此这个特定示例至少是临界值。我会让其他人做确切的语言律师,并简单地声明,当使用支持匿名结构扩展的最新编译器时,代码几乎肯定会按预期执行。

如果这些非标准要求中的任何一个困扰您,请删除结构和 union ,以便数组是唯一的数据成员。然后为符号名称添加函数,例如T& x() { 返回数据[0]; ,只是稍微麻烦一点。

关于c++ - 用 C++ 编写广义 vector 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21033009/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com