Passing a temporary structure as a template argument

I am creating a vector class and trying to figure out ways to reuse the maximum amount of code for different size vectors. Here is a basic example:

template<typename T, unsigned int D> class Vector { public: union { T v[D]; struct { /* T x; * T y; * T z; * T w; */ }; }; Vector() { for(unsigned int i=0; i<D; ++i) (*this)[i] = T(0); } Vector(T scalar) { for(unsigned int i=0; i<D; ++i) (*this)[i] = scalar; } inline T operator[](int i) { return (*this).v[i]; } }; 

I want member variables to be publicly available. Example:

 Vector<float,2> vec; printf("X: %.2f, Y: %.2f\n", vec.x, vec.y); 

What I would like to do is something like this:

 template<typename T> class Vector2 : public Vector<T,2, struct { T x; T y; }> {}; template<typename T> class Vector3 : public Vector<T,2, struct { T x; T y; T z; }> {}; 

and redefine the structure in the union:

 template<typename T, unsigned int D, struct C> class Vector { public: union { T v[D]; // Place the passed struct here }; }; 

Is there any possible way to do this? I do not want to use anything other than the standard library, if possible. Thanks in advance.

EDIT: After reading all the answers, I realized that the way you use unions is wrong! Thanks @MM for this. Since then, I have chosen a different route, but I have chosen the answer that best matches what I was looking for at that time. Thank you again for all the welcome answers below!

+6
source share
3 answers

If you understood correctly, your main goal was to declare the field order corresponding to the elements of the array of the template class. You cannot do this directly, because templates do not accept an inline type as a parameter. To get around the problem, you could play with non-pig type template parameters to associate some labels with a given array index:

 #include <cstdio> #include <unordered_map> #include <utility> struct Label { } x, y, z, w; template <Label&... labels> struct Pack { }; template <class, class> struct VectorParent; template <Label&... labels, size_t... Is> struct VectorParent<Pack<labels...>, std::index_sequence<Is...>> { static std::unordered_map<Label *, size_t> label_map; }; template <Label&... labels, size_t... Is> std::unordered_map<Label *, size_t> VectorParent<Pack<labels...>, std::index_sequence<Is...>>::label_map = {{&labels, Is}...}; struct LabelNotFound { }; template <class T, size_t N, Label&... labels> struct Vector:VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>> { static_assert(N == sizeof...(labels), "the cound of labels should corespond to the number of elements of the vector"); using VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>>::label_map; T t[N]; T &operator->*(Label& l) { auto it = label_map.find(&l); if (it == label_map.end()) throw LabelNotFound{}; return t[it->second]; } }; int main() { Vector<float,2,x,y> vec; vec->*x = 10.0f; printf("X: %.2f, Y: %.2f\n", vec->*x, vec->*y); // prints: X: 10.00, Y: 0.00 //vec->*w = 10.1f; //would throw an exception LabelNotFound } 
+1
source

What you are trying to do is not allowed.
Anyway, you can do this:

 template<typename T> struct S { T x; T y; }; template<typename T> class Vector2 : public Vector<T,2,S<T>> {}; 

Or that:

 template<typename T> class Vector2 : public Vector<T,2,S> {}; 

In the second case, Vector can be defined as:

 template<typename T, unsigned int D, template<typename> class S> class Vector { using MyStruct = S<T>; // ... union { T v[D]; MyStruct myStruct; }; }; 
+4
source

It does not scale very well for big D , but if you immediately after four or six options, I imagine, you can partially classify the base class:

 #include <iostream> template<typename T, size_t D> struct VectorBase; template<typename T> struct VectorBase<T, 2> { constexpr VectorBase() : v{} {} union { T v[2]; struct { T x, y; }; }; }; template<typename T> struct VectorBase<T, 3> { constexpr VectorBase() : v{} {} union { T v[3]; struct { T x, y, z; }; }; }; template<typename T> struct VectorBase<T, 4> { constexpr VectorBase() : v{} {} union { T v[4]; struct { T x, y, z, w; }; }; }; template<typename T, size_t D> struct Vector : public VectorBase<T, D> { using VectorBase<T, D>::v; using size_type = decltype(D); using value_type = T; constexpr Vector() : VectorBase<T,D>{} {} constexpr Vector(T scalar) { std::fill(std::begin(v), std::end(v), scalar); } constexpr T& operator[](size_type i) const noexcept { return v[i]; } constexpr const T& operator[](size_type i) noexcept { return v[i]; } constexpr size_type size() const noexcept { return D; } constexpr T* data() noexcept { return &v[0]; } constexpr const T* data() const noexcept { return &v[0]; } }; template<typename T> using Vector2 = Vector<T, 2>; template<typename T> using Vector3 = Vector<T, 3>; template<typename T> using Vector4 = Vector<T, 4>; int main() { Vector3<int> v{1}; std::cout << v[0] << ", " << vz << "\n"; return 0; } 

Live demo: http://ideone.com/T3QHoq

+2
source

All Articles