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;