sheep sheep - 3 months ago 15
C++ Question

Passing temporary struct as template argument

I'm in the process of creating a vector class and am trying to figure out ways to reuse the maximum amount of code for different size vectors.
Here's 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 the member variables to be publicly accessible. Ex:

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


What I'd like to do is something along the lines of 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 have it override a struct 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 feasible way to do this? I do not want to use anything other than the standard library if possible. Thanks in advance.

EDIT: After reading upon all of the answers, I have understood that the way I am using unions is incorrect! Thank you to @M.M for pointing this out. I have since chosen to go a different route, but I have selected the answer that best fit what I was looking for at the time. Once again, thank you for all of the welcomed responses below!

Answer

If I understood you correctly your main purpose was to to declare order of fields that corresponds to the array elements of templated class. You cannot do this directly as templates does not accept inline type as parameter. To workaround the problem you could play with non-type template parameters to bind some labels to given index of an array:

#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}...};

template <class T, size_t N, Label&... labels>
struct Vector:VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>> {
   static_assert(N == sizeof...(labels), 
       "Count of labels should correspond to the number of elements of the vector");
   T t[N];
   T &operator->*(Label& l) {
      return t[VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>>::label_map[&l]];
   }
};

int main() {
    Vector<float,2,x,y> vec;
    vec->*x = 10.0f;
    printf("X: %.2f, Y: %.2f\n", vec->*x, vec->*y);
}
Comments