c ++数组元素的别名

Jen*_*vig 8 c++ arrays alias templates

我有一个(列)Vector类,它包含一个可以访问的值数组:

Vec<int, 4> v();
v[0] = -2; // <- set first value to -2
v[1] = 1; // <- set second value to 1
....
Run Code Online (Sandbox Code Playgroud)

但这是我的问题:我如何为v[0], v[1], v[2], v[3]?创建别名?我想将前4个值定义为v.x, v.y, v.z, v.w:

Vec<int, 4> v();
v.x = -2; // <- set first value to -2
v.y = 1; // <- set second value to 1
v.z = 4; // <- set third value to 4
v.w = 2; // <- set fourth value to 2
Run Code Online (Sandbox Code Playgroud)

我应该能够分配读取值,我不希望它们看起来像一个函数,所以访问第一个值,如:

Vec<int, 4> v();
v.x() = -2; // <- set first value to -2
Run Code Online (Sandbox Code Playgroud)

没有好处.最重要的是,矢量类是模板化的,x应该仅定义为dimensions >= 1,而y仅用于dimenions >= 2...等等......我如何实现这一目标?

编辑: Vector类与std :: vector无关,它是一个类似于数组的数学向量,因为它具有固定的大小,仅用于数学运算.(将Vector重命名为Vec).

我尝试过的:

矩阵类:

template <typename T, size_t ROWS, size_t COLS>
class Matrix {

    public:
        T& operator[] (size_t idx) {return m_matrix[idx];}
        T operator[] (size_t idx) const {return m_matrix[idx];}

    private:
        m_matrix[ROWS * COLS]
};
Run Code Online (Sandbox Code Playgroud)

矢量类:

template <typename T, size_t N>
class Vec: public Matrix<T, 1, N>{

    public:

        T& x() {return (*this)[0];}
        T x() const {return (*this)[0];}

        T& y() {return (*this)[1];}
        T y() const {return (*this)[1];}

        T& z() {return (*this)[2];}
        T z() const {return (*this)[2];}

        T& w() {return (*this)[3];}
        T w() const {return (*this)[3];}
};
Run Code Online (Sandbox Code Playgroud)

这很有效,如果没有为这个维度定义,我很容易使用enable_if来删除函数,但这在语法上并不令人满意.我试过使用引用:

template <typename T, size_t N>
class Vec: public Matrix<T, N, 1>{

    public:

        T& x = (*this)[0];
        T& y = (*this)[1];
        T& z = (*this)[2];
        T& w = (*this)[3];
};
Run Code Online (Sandbox Code Playgroud)

但这不起作用,它不会给我一个错误,但它也没有正确设置值,当我在设置它们未定义后访问它们.

编辑nr 2:可能只存在一个更简单的解决方案,当我最后一次使用Visual Studio社区2015的默认编译器编译引用时,它就可以工作了.但是当我使用GNU GCC编译器在Code :: Blocks中编译它时,它却没有.标准说什么?我的解决方案是否允许使用引用,哪个编译器是错的?

ois*_*syn -3

你可以这样做:

// General case uses an array
template<class T, std::size_t N>
class VectorData
{
private:
    T m_data[N];

public:
    T& operator[](int i) { return m_data[i]; }
    const T& operator[](int i) const { return m_data[i]; }
};

// Specializations for various N (4 shown here)
template<class T>
class VectorData<T, 4>
{
public:
    T x, y, z, w;

    T& operator[](int i) { return (&x)[i]; }  // WARNING, see note below
    const T& operator[](int i) const { return (&x)[i]; }
};


template<class T, std::size_t N>
struct Vector : public VectorData<T, N>
{
    // your other Vector stuff here
};
Run Code Online (Sandbox Code Playgroud)

注意:正如下面的一位评论者正确指出的那样,这假设数组元素在内存中的布局与变量列表完全相同(iow,T[4]并且struct { T x,y,z,w; }与布局兼容),以便该&x[i]部分正常工作。标准不保证这一点,因此此代码将产生未定义的行为。在实践中,这很好,而且这样做的性能会更高。如果您需要一个可移植的、符合标准的实现,您可以选择使用switchinside VectorData::operator[],正如另一个答案所建议的那样。可以在此处看到生成的代码的差异。

如果你确实需要 Vector 从 Matrix 派生,这样的事情仍然是可能的。总的想法就是将存储和功能解耦。您可以创建一些具有所有功能的通用 Matrix 类,该类具有用于存储的额外模板参数。然后 Vector 可以只提供自己的存储类型。

就像是:

// Generic matrix storage
template<class T, std::size_t N>
class MatrixData
{
private:
    T m_data[N];

public:
    T& operator[](int i) { return m_data[i]; }
    const T& operator[](int i) const { return m_data[i]; }
};

// Generic matrix class
template<class T, std::size_t ROWS, std::size_t COLS, class Storage = MatrixData<T, ROWS*COLS>>
class Matrix : public Storage
{
    // Matrix functionality here
};



// Specialized storage for Vectors, generic version
template<class T, std::size_t N>
class VectorData : public MatrixData<T, N> { };

// Specialized storage for Vector<T, 4>
template<class T>
class VectorData<T, 4>
{
public:
    T x, y, z, w;

    T& operator[](int i) { return (&x)[i]; }
    const T& operator[](int i) const { return (&x)[i]; }
};

template<class T, std::size_t N>
struct Vector : public Matrix<T, N, 1, VectorData<T, N>>
{
    // your other stuff here
};
Run Code Online (Sandbox Code Playgroud)

  • 当 i 大于 0 时,`return (&amp;x)[i]` 为 UB。只能在数组中使用指针算术。不过,使用“switch”块就可以了。 (4认同)
  • 我对此绝对确定。 (3认同)
  • “实际上,这很好,而且这样做的性能要好得多。” 这**不太**好。它可能看起来对你有用,但它是 UB,你很容易在某些时候出现不需要的行为,它可能在 99% 的情况下“有效”,但在另外 1% 的情况下会出现神秘且难以调试的问题,它可能看起来可以工作,但当您更改编译器版本等时会停止工作。不建议这样做。这是坏的。 (2认同)