C ++ Alias ​​for array element

I have a Vector class (column) that contains an array of values ​​that can be accessed, for example:

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

But here is my question: how to create an alias for v[0], v[1], v[2], v[3] ? I would like to define the first 4 values ​​as vx, vy, vz, vw :

 Vec<int, 4> v(); vx = -2; // <- set first value to -2 vy = 1; // <- set second value to 1 vz = 4; // <- set third value to 4 vw = 2; // <- set fourth value to 2 

I have to assign and read values, and I don't want them to look like a function, so access to the first value:

 Vec<int, 4> v(); vx() = -2; // <- set first value to -2 

Not good. In addition, the templated vector pattern and x should be defined only for dimensions >= 1 , and y only for dimenions >= 2 ... etc. How to achieve this?

Edit: The Vector class has nothing to do with std :: vector, it is a mathematical vector that looks like an array, because it has a fixed size and is used only for mathematical operations. (renaming a vector in Vec).

What I tried:

Matrix class:

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

Vector class:

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

This works, and I can easily use enable_if to remove functions if it is not defined for this dimension, however it is not syntactically pleasing. Ive tried using links:

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

But this will not work, it does not give me an error, but it also does not set the values ​​correctly when I access them after setting undefined.

Edit nr 2: there may be an even simpler solution when my last link attempt compiles using the default Visual Studio community 2015 compiler, then it works. But when I compile it in Code :: Blocks using the GNU GCC compiler, it is not. What does the standard say? Is my solution allowed using valid references, which compiler is incorrect?

+7
c ++ arrays alias templates
source share
3 answers

You can do something like:

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

Note As one of the commentators below correctly noted, this suggests that the elements of the array are laid out in memory in the same way as the list of variables (iow, T[4] and struct { T x,y,z,w; } compatible with layouts) for the part &x[i] . The standard does not guarantee this, and therefore this code will give undefined behavior. In practice, this is great, and doing it this way is more effective. If you need a portable standardized implementation, you can select switch inside VectorData::operator[] , as another answer suggested. The difference in code generation can be seen here .

If you really need a vector to get from Matrix, something like this is still possible. The general idea is that you turn off storage and functionality. You can create some common Matrix class with all the functionality, which has an additional template parameter for storing it. Then the vector can simply provide its own storage type.

Something like:

 // 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 }; 
-3
source share

It:

 template <typename T, int D> struct Vec; // You have to manually specialize for all needed sizes template <typename T> struct Vec<T, 4> { T x, y, z, w; T &operator[](int index) { switch (index) { default: // throw or something? case 0: return x; case 1: return y; case 2: return z; case 3: return w; } } const T &operator[](int index) const { switch (index) { default: // throw or something? case 0: return x; case 1: return y; case 2: return z; case 3: return w; } } }; 

The switch ing index is not optimal, but at least it is defined.

For matrices, I prefer to use Vec<Vec<T, Height>, Width> , which makes the notation mat[x][y] . (If you want, replace x and y .)

+2
source share

If you are making a C ++ 14 decision, I suggest creating an indexed wrapper with a pattern for x , y , z and w , referencing T variables

 template <typename T, std::size_t> struct wrapper { wrapper (T const &) {} }; template <typename T> struct wrapper<T, 0U> { T & x; }; template <typename T> struct wrapper<T, 1U> { T & y; }; template <typename T> struct wrapper<T, 2U> { T & z; }; template <typename T> struct wrapper<T, 3U> { T & w; }; 

The following shell is std::array , which should be inherited before indexed wrappers

 template <typename T, std::size_t N> struct arrayWrp { std::array<T, N> arr {}; }; 

Now you can define a helper struct VecH as follows

 template <typename T, std::size_t ... Is> struct VecH<T, std::index_sequence<Is...>> : public arrayWrp<T, sizeof...(Is)>, public wrapper<T, Is>... { using arrayWrp<T, sizeof...(Is)>::arr; VecH () : arrayWrp<T, sizeof...(Is)>{}, wrapper<T, Is>{ arr[Is] }... { } T & operator[] (std::size_t i) { return arr[i]; } T const & operator[] (std::size_t i) const { return arr[i]; } }; 

which inherit from arrayWrp and from all wrapper<T, Is> , and the references of x , y , z and w to arr[0] , arr[1] , arr[2] and arr[3] reasonable

So Vec become

 template <typename T, std::size_t N> struct Vec : public VecH<T, std::make_index_sequence<N>> { }; 

Below is a complete working example

 #include <array> #include <iostream> #include <type_traits> template <typename T, std::size_t> struct wrapper { wrapper (T const &) {} }; template <typename T> struct wrapper<T, 0U> { T & x; }; template <typename T> struct wrapper<T, 1U> { T & y; }; template <typename T> struct wrapper<T, 2U> { T & z; }; template <typename T> struct wrapper<T, 3U> { T & w; }; template <typename T, std::size_t N> struct arrayWrp { std::array<T, N> arr {}; }; template <typename, typename> struct VecH; template <typename T, std::size_t ... Is> struct VecH<T, std::index_sequence<Is...>> : public arrayWrp<T, sizeof...(Is)>, public wrapper<T, Is>... { using arrayWrp<T, sizeof...(Is)>::arr; VecH () : arrayWrp<T, sizeof...(Is)>{}, wrapper<T, Is>{ arr[Is] }... { } T & operator[] (std::size_t i) { return arr[i]; } T const & operator[] (std::size_t i) const { return arr[i]; } }; template <typename T, std::size_t N> struct Vec : public VecH<T, std::make_index_sequence<N>> { }; int main () { Vec<int, 4U> v4; v4.x = 1; v4.y = 2; v4.z = 3; v4.w = 4; std::cout << "v4: "; for ( auto ui = 0U ; ui < 4U ; ++ui ) std::cout << ' ' << v4[ui]; std::cout << std::endl; Vec<int, 5U> v5; // also over 4 Vec<int, 3U> v3; v3.x = 10; v3.y = 20; v3.z = 30; // v3.w = 40; // compilation error } 

If you don't like using the VecH struct helper, you can use the partial specialization and the default template parameter std::make_index_sequence<N> as follows

 template <typename, std::size_t N, typename = std::make_index_sequence<N>> struct Vec; template <typename T, std::size_t N, std::size_t ... Is> struct Vec<T, N, std::index_sequence<Is...>> : public arrayWrp<T, N>, public wrapper<T, Is>... { using arrayWrp<T, sizeof...(Is)>::arr; Vec () : arrayWrp<T, sizeof...(Is)>{}, wrapper<T, Is>{ arr[Is] }... { } T & operator[] (std::size_t i) { return arr[i]; } T const & operator[] (std::size_t i) const { return arr[i]; } }; 

but I don’t know if this is a good idea: someone might try using Vec as follows

 Vec<int, 3U, std::index_sequence<0, 2, 5>> v; 
0
source share

All Articles