Reputation: 979
Basically, what i'm trying to do is build a Vector template, with two arguments: dimensions, and variable type.
template <typename Type, unsigned ElementCount>
class TVector
{
private:
public:
union
{
struct
{
Type X, Y, Z, W;
};
struct
{
Type Red, Green, Blue, Alpha;
};
Type Values[ElementCount];
};
}
It all works ok, but as you may have noticed, this is only for 4-element vectors, since only the Values variable is dependent on ElementCount. ElementCount=1 declares only X and Red, 2 declares Y and Green, and so on... So, what i wanted was to have the other variables being declared also depending on the ElementCount value.
Is it at all possible? I don't think so, but wanted to make sure, anyway.
I was thinking of declaring that whole union separately and passing it along as a template parameter, but that's ugly as hell....
EDIT: Dammit. Now i remembered something... What about the constructor-by-value?
The argument count is dependent of the template parameter ElementCount... How to do this?
Upvotes: 0
Views: 177
Reputation: 979
Ok, first of all, a big thank you for everyone, for all the ideas. I finally managed to do what i wanted, using a mix of all you suggested.
second, let me explain, then. I wanted to rewrite my math library. I basically had a class for 2d, 3d and 4d vectors each. It was stupid, since most of the code is the same, so i decided to try to refactor using templates.
I also had a small class named RGB and another called RGBA for obvious reasons :).
And as such, i embarked on this adventure with templates ( i'm not a big fan, but mainly because i can't understand them. they're certainly very useful ).
So, after several failed tries, I changed approach. The final result is a mix of all the above and the kitchen sync. A small taste, including member functions ( i had some trouble with those ), the union with the named member variables is available here: http://goo.gl/4Zlt20
Now, for one final question, if i may...
It all works the way i want it, but for some reason, i can't get rid of that "this->" on the inline functions. Can anyone explain why?
Thanks.
Upvotes: 0
Reputation: 208456
I would avoid specialization at this level, rather do it inside the union itself:
template <typename T> struct X { T x; };
template <typename T> struct XY { T x, y; };
...
template <typename T, int Count>
struct CountToXYZWType {};
template <typename T> struct CountToXYZWType<T,1> { typedef X<T> type; };
template <typename T> struct CountToXYZWType<T,2> { typedef XY<T> type; };
...
template <typename T, int Count>
struct TVector {
union {
typename CountToXYZWType<Count>::type;
// similarly CountToColorType<Count> ...
T values[Count];
}
...
};
Upvotes: 0
Reputation: 1086
You don't need to pass in the whole union -- just the struct and the type of the fields. I've also added a syntactic sugar in operator-> so you don't have to reference the .Names part if you don't wish.
#include <iostream>
struct PointStruct {
int X;
int Y;
int Z;
};
struct ColorStruct {
int Red;
int Green;
int Blue;
int Alpha;
};
template <typename Type, typename Struct>
class TVector
{
public:
const static int LEN = sizeof(Struct) / sizeof(Type);
union
{
Struct Names;
Type Values[LEN];
};
Struct* operator->() { return &Names; }
const Struct* operator->() const { return &Names; }
};
int main(int argc, const char** argv) {
TVector < int, PointStruct > points;
points.Names.X = 55;
points.Names.Y = -67;
points.Names.Z = 42;
for (int x = 0; x < points.LEN; ++x) {
std::cout << "points[" << x << "]: " << points.Values[x] << std::endl;
}
points.Values[1] = 135;
std::cout << "points->Y: " << points->Y << std::endl;
TVector < int, ColorStruct > colors;
colors.Names.Red = 1;
colors.Names.Green = 2;
colors.Names.Blue = 3;
colors.Names.Alpha = 4;
for (int x = 0; x < colors.LEN; ++x) {
std::cout << "colors[" << x << "]: " << colors.Values[x] << std::endl;
}
}
With g++ 4.3 I get
points[0]: 55
points[1]: -67
points[2]: 42
points->Y: 135
colors[0]: 1
colors[1]: 2
colors[2]: 3
colors[3]: 4
Upvotes: 0
Reputation: 409482
You could do it with partial specialization. Something like
template<typename T, unsigned N>
struct S
{
union
{
struct
{
T X, Y, Z, W;
};
struct
{
T Red, Green, Blue, Alpha;
};
T Values[N];
};
};
template<typename T>
struct S<T, 1>
{
union
{
struct
{
T X;
};
struct
{
T Red;
};
T Values[1];
};
};
int main()
{
using S1 = S<char, 1>;
using S5 = S<char, 5>;
std::cout << "sizeof(S1) = " << sizeof(S1) << '\n';
std::cout << "sizeof(S5) = " << sizeof(S5) << '\n';
}
It should print
sizeof(S1) = 1 sizeof(S5) = 5
Also, doing e.g.
S1 s1;
s1.Y = 0;
should give you an error that the structure have no member Y
.
Yes it's a lot more to write (or copy-paste) but it should solve your problem.
Upvotes: 1