In C++, I'm trying to create a specialized point class as a union, like so:
union point
{
struct { float x, y, z; };
float val[3];
float operator[](unsigned i) { return val[i]; }
};
So that I can access the point as an array or as multiple points, for readability.
However, let's say that I want to generalise this a bit:
template<unsigned n>
union point
{
struct { float ???; };
float val[n];
float operator[](unsigned i) { return val[i]; }
};
What can I put for ???? I could have x, x, y, x, y, z, or x, y, z, w depending on what n is. Solution? Forward declarations!
template<unsigned n>
union point
{
struct coords;
float val[n];
float operator[](unsigned i) { return val[i]; }
};
template<>
struct point::coords<3>
{
float x, y, z;
};
// ...
But this doesn't appear to work. Under the GCC 4.6, it compiles, however, whenever that I try to use the members, like so:
point<3> val;
val.x;
I get the error:
error: ‘union point<3>’ has no member named ‘x’
Even if I change val.x to val.coords::x, I still get the error:
error: ‘union point<3>::coords’ is not a base of ‘union point<3>’
Adding using coords; in the union definition didn't help, either.
Is there any way to accomplish this under the GCC 4.6? Is there a different method of doing this? Is it even possible?
I would suggest using variadic macro to define your union<N> templates.
template<unsigned int N>
union point; // declared and undefined
#define DECLARE_POINT(NUM, ...) \
template<> \
union point<NUM> \
{ \
struct { float __VA_ARGS__; }; \
float val[NUM]; \
}
#undef DECLARE_POINT
Having done this, you can simply declare/define your various combinations for coordinates (before #undef in this case):
DECLARE_POINT(1, x);
DECLARE_POINT(2, x, y);
DECLARE_POINT(3, x, y, z);
that is equivalent to,
template<> union point<1> { struct { float x; }; float val[1]; };
template<> union point<2> { struct { float x, y; }; float val[2]; };
template<> union point<3> { struct { float x, y, z; }; float val[3]; };
It can be used in the same way you asked:
point<3> p;
p.z = 0;
Also, you can put a cross check using some template trickery (static_assert) to check the number arguments(e.g. 1,2,3,...) match the total argument passed (e.g. x,y,z,...).
This line inside your union:
struct coords;
forward-declares the type coords, but there's no struct coords field in your templated union.
Besides, only members of anonymous structures can be accessed as top-level fields of an union. For instance:
union foo {
struct { // anonymous struct
short i;
short j;
};
int k;
};
foo f;
// it's possible to access the fields of the anonymous struct as if they were
// direct members of the union
f.i = 4;
f.j = 8;
std::cout << f.k;
I'm not sure you'll be able to do that if you only specialize the inner struct type.
However, this works:
template<unsigned n>
union point;
template<>
union point<2> {
struct { float x, y; };
float val[2];
};
template<>
union point<3> {
struct { float x, y, z; };
float val[3];
};
There is a number of downsides though; the main one being that you'll have to redefine operator[] for each version of point.
I know how to use templates but I'm no template god, so it's not out of question that a clever trick exists.
Related
I have a vector 3D class
class Vector3D{
public: float x; float y; float z;
//some functions, e.g. operator+ - * /
//some 3D-specific function
};
and a vector N-D class.
template<int constSize> class VecFloatFix{
float database[constSize];
//some functions, e.g. operator+ - * /
};
I noticed that there is code-duplication between two classes, so I think I should make Vector3D derived from VecFloatFix<3> :-
class Vector3D : public VecFloatFix<3>{
//some 3D-specific function
};
Everything seems to be good, except that there are a lot of user code access Vector3D::x,y,z directly.
Is it possible to make Vector3D derived from VecFloatFix<3> while not break user's code?
My best guess is around :-
template<int constSize> class VecFloatFix{
union{
float database[constSize];
float x,y,z; ????? sound like a hack
}
//some functions, e.g. operator+ - * /
};
Edit: Hardcoding x,y,z into VecFloatFix is unsustainable.
If I have a new class Vector2D that derived from VecFloatFix<2>, Vector2D::z will compile fine (dangerous).
Here is a version that only exposes x, y, z components for vectors of size 3. Obviously other sizes may also be specialized.
template<int constSize> struct VecFloatStorage
{
float database[constSize];
};
template<> struct VecFloatStorage<3>
{
union
{
float database[3];
struct { float x, y, z; };
};
};
template<int constSize> class VecFloatFix : public VecFloatStorage<constSize>
{
public:
// Methods go here.
};
I don't know if the standard guarantees struct { float x, y, z; } to have the same memory layout as float data[3], however in practice I am pretty certain that assumption holds.
The GLM library is using a similar trick, except they don't have an array member at all, instead providing an indexing operator that returns (&this->x)[idx].
This is by no ways guaranteed to work as it uses implementation-defined and possibly undefined behaviour. A sensible implementation will probably behave as expected though.
template<int constSize>
class VecFloatFix{
public:
union {
float database[constSize];
struct {
int x, y, z;
};
};
};
This also leaves database public. Don't see a way around this, but no big deal since you provide operator[] anyway.
This assumes constSize >= 3. If you need smaller sizes, this is doable through a bit more hackery. All vectors will have x y and z members but only 3D and above will have them all usable. The 2D vector will have only x and y usable (any use of z is likely to result in an error) and the 1D vector will have just x. Note I refuse to take responsibility for any of the following.
template<int constSize>
class VecFloatFix{
public:
union {
float database[constSize];
struct {
float x;
};
struct {
spacer<constSize, 1> sp1;
typename spacer<constSize, 1>::type y;
};
struct {
spacer<constSize, 2> sp2;
typename spacer<constSize, 2>::type z;
};
};
};
where spacer is defined this way:
template <int N, int M, bool enable>
struct filler;
template <int N, int M>
struct filler<N, M, true>
{
float _f[M];
typedef float type;
};
template <int N, int M>
struct filler<N, M, false>
{
struct nothing {};
typedef nothing type;
};
template <int N, int M>
struct spacer
{
filler<N, M, (N>M)> _f;
typedef typename filler<N, M, (N>M)>::type type;
};
Test drive:
VecFloatFix<4> vec4;
VecFloatFix<3> vec3;
VecFloatFix<2> vec2;
VecFloatFix<1> vec1;
`smoke test`
vec3.database[0] = 42;
vec2.database[1] = 99;
std::cout << vec3.x << std::endl;
std::cout << vec2.y << std::endl;
// make sure `y` aliases `database[1]`
std::cout << & vec2.y << std::endl;
std::cout << & vec2.database[1] << std::endl;
// make sure sizes are as expected
std::cout << sizeof(vec4) << " " << sizeof (vec3) << " " << sizeof(vec2) << " " << sizeof(vec1) << std::endl;
is there a way how to simulate union behavior? See following code:
// this is ideal interface, which I would like to simulate
struct IdealInterface{
union{
struct{float r,g,b;};
struct{float x,y,z;};
};
};
// this is real parent object I should not change
struct Parent{
float r, g, b;
};
// this interface has ok behavior,
// but sizeof(Child0) != sizeof(Parent)
// which causes problems
struct Child0:public Parent{
float & x, & y, & z;
Child0() : Parent(), x(r), y(g), z(b){ };
};
// this has ok size, but interface is different
struct Child1:public Parent{
float & x(){ return r; }
float & y(){ return g; }
float & z(){ return b; }
};
So as described, I should keep Parent class, and I should derive my child class from Parent. I should not create different types and play with the type conversions. Thus, is it possible to create derived class (form Parent) with the same interface as IdealInterface class has?
If you mean identical behavior to a union then no, not without actually using a union.
You could always just hide the underlying data:
class Vertex
{
Vertex();
Vertex(float,float,float);
float& x() { return r;}
float& y() { return g;}
float& z() { return b;}
float& r() { return r;}
float& g() { return g;}
float& b() { return b;}
void r(float rComponent) { this->r = rComponent; }
...
private:
float r, g, b;
}
However, the downside to this approach is you must call the methods vs. accessing the underlying variable like you can do with the union.
If you want:
Vertex v;
v.x = 1.0f
Then you would want to use a union.
Answer:
Firstly, I have some words for commentators. I asked a pretty straight question. What I got? For example answers about sizeof properties, which were not posed (btw, yeah in this case I have guarantee about sizeof - this is c++, not a kind of today common wild language).
Why I cannot use IdealInterface. Problem is more complex. I want to edit bigger pack of code with introduced constraints and dependencies. Thus this is the question and I cannot redefine question, however it implies simpler solution.
Answer: NO, it is not possible.
Why? It is based on properties of anonymous structs and unions.
Nearest approach: For my purpose, nearest approach is to use memory model as parameter.
struct BASIC_MEMORY_MODEL{
float x, y, z;
BASIC_MEMORY_MODEL() :x(), y(), z(){}
};
struct ADVANCED_MEMORY_MODEL{
union{
struct { float x, y, z; };
struct { float r, g, b; };
};
ADVANCED_MEMORY_MODEL() :x(), y(), z(){}
};
template<typename MEMORY_MODEL = BASIC_MEMORY_MODEL>
struct ParentBase : public MEMORY_MODEL{};
typedef ParentBase<> Parent;
struct Child : public ParentBase < ADVANCED_MEMORY_MODEL > {};
Is it possible define a union temporary inside the function call, rather than defining it previously and then passing it in the parameters?
Example:
union data_t{
double delaySeconds;
float scale;
float rotation;
};
void someFunction(data_t){}
Now I want to call someFunction, using whatever element of the union is appropriate:
someFunction(WHAT DO I PUT HERE);
For example, if you are passing to a function that expects a type that includes a constructor, you can define your temporary right there in the function call. But I've tried a variety of ways with this union with no luck. For example, suppose I want to pass a float assigned to scale:
someFunction(data_t.scale(2.0));
You can define a constructor for your union for initializing the members. But, you need a mechanism to distinguish which field was set. Below, I define a helper enum, and extend your data_t to allow for inheritance and member distinction.
enum data_t_type { DelaySeconds, Scale, Rotation };
struct data_t {
union {
double delaySeconds;
float scale;
float rotation;
};
union {
unsigned char flags;
struct {
unsigned char isDelaySeconds : 1;
unsigned char isScale : 1;
unsigned char isRotation : 1;
};
};
data_t () : flags(0) {}
};
Now, the initialization is actually done with a template that takes the data_t_type as a parameter.
template <data_t_type> struct data_type {};
template <> struct data_type<DelaySeconds> : data_t {
data_type (double x) { delaySeconds = x; isDelaySeconds = 1; }
};
template <> struct data_type<Scale> : data_t {
data_type (float x) { scale = x; isScale = 1; }
};
template <> struct data_type<Rotation> : data_t {
data_type (float x) { rotation = x; isRotation = 1; }
};
So now, you can call your function like so:
someFunction(data_type<Scale>(2.0));
Since a data_type<> is a data_t, someFunction() gets the right type.
This question is my mistake.
The code described below is being built well with no problem.
I have this class.
Vector.h
struct Vector
{
union
{
float elements[4];
struct
{
float x;
float y;
float z;
float w;
};
};
float length();
}
Vector.cpp
float Vector::length()
{
return x; // error: 'x' was not declared in this scope
}
How to access the member x,y,z,w?
You need an instance of your struct inside the anonymous union. I don't know exactly what you want to achive, but e.g. something like this would work:
struct Vector
{
union
{
float elements[4];
struct
{
float x, y, z, w;
}aMember;
};
float length() const
{
return aMember.x;
}
};
What you have created is not an anonymous member, but anonymous type (which is useless by itself). You have to create a member of your anonymous type. This concerns both your struct and your union.
Adjust the header like this:
struct Vector
{
union
{
float elements[4];
struct
{
float x;
float y;
float z;
float w;
} v;
} u;
float length();
};
Now you can access your members like this:
u.elements[0] = 0.5f;
if(u.v.x == 0.5f) // this will pass
doStuff();
There's no way to do something like this, in C++ is there?
union {
{
Scalar x, y;
}
Scalar v[2];
};
Where x == v[0] and y == v[1]?
Since you are using C++ and not C, and since they are of the same types, why not just make x a reference to v[0] and y a reference to v[1]
How about
union {
struct {
int x;
int y;
};
int v[2];
};
edit:
union a {
struct b { int first, second; } bee;
int v[2];
};
Ugly, but that's more accurate
Try this:
template<class T>
struct U1
{
U1();
T v[2];
T& x;
T& y;
};
template<class T>
U1<T>::U1()
:x(v[0])
,y(v[1])
{}
int main()
{
U1<int> data;
data.x = 1;
data.y = 2;
}
I've used something like this before. I'm not sure its 100% OK by the standard, but it seems to be OK with any compilers I've needed to use it on.
struct Vec2
{
float x;
float y;
float& operator[](int i) { return *(&x+i); }
};
You can add bounds checking etc to operator[] if you want ( you probably should want) and you can provide a const version of operator[] too.
If you're concerned about padding (and don't want to add the appropriate platform specific bits to force the struct to be unpadded) then you can use:
struct Vec2
{
float x;
float y;
float& operator[](int i) {
assert(i>=0);
assert(i<2);
return (i==0)?x:y;
}
const float& operator[](int i) const {
assert(i>=0);
assert(i<2);
return (i==0)?x:y;
}
};
I was looking for a similair thing and eventually came up with a solution.
I was looking to have a data storage object that I could use as both an array of values and as individual values (for end-user flexibility in writing Arduino libraries).
Here is what I came up with:
class data{
float _array[3];
public:
float& X = _array[0];
float& Y = _array[1];
float& Z = _array[2];
float& operator[](int index){
if (index >= 3) return _array[0]; //Make this action whatever you want...
return _array[index];
}
float* operator&(){return _array;}
};
int main(){
data Test_Vector;
Test_Vector[0] = 1.23; Test_Vector[1] = 2.34; Test_Vector[2] = 3.45;
cout<<"Member X = "<<Test_Vector.X;
cout<<"Member Y = "<<Test_Vector.Y;
cout<<"Member Z = "<<Test_Vector.Z;
float* vector_array = &Test_Vector;
cout<<"Array = {"<<vector_array[0]<<", "<<vector_array[1]<<", "<<vector_array[2]<<"}";
}
Thanks to Operator overloading, we can use the data object as if was an array and we can use it for pass-by-reference in function calls (just like an array)!
If someone with More C++ experience has a better way of applying this end product, I would love to see it!
EDIT: Changed up the code to be more cross-platform friendly
Given your example:
union
{
struct
{
Scalar x, y;
};
Scalar v[2];
};
As others have noted, in general, the standard does not guarantee that there will be no padding between x and y, and actually compilers inserting padding in structures is pretty common behavior.
On the other hand, with solutions like:
struct U
{
int v[2];
int& x;
int& y;
};
U::U()
: x(v[0])
, y(v[1])
{}
what I don't like mainly is the fact that I have to mention x, y twice. For cases where I have more than just a few elements (say 10), this becomes much less readable and harder to maintain - e.g. if you want to change the order of x,y then you have to change the indexes below too (well not mandatory but otherwise order in memory wouldn't match order of fields, which would not be recommended). Also, U can no longer be a POD since it needs a user-defined constructor. And finally, the x & y references consume additional memory.
Hence, the (acceptable for me) compromise I've come up with is:
struct Point
{
enum CoordType
{
X,
Y,
COUNT
};
int coords[CoordType::COUNT];
};
typedef Point::CoordType PtCoord;
With this you can then do:
Point p;
for ( int i = 0; i < PtCoord::COUNT; i++ )
p.coords[i] = 100;
std::cout << p.coords[PtCoord::X] << " " << p.coords[PtCoord::Y] << std::endl;
// 100 100
A bit sophisticated but I prefer this over the references suggestion.
Depending on what "Scalar" is, yes, you can do that in C++. The syntax is almost exactly (maybe even exactly exactly, but I'm rusty on unions) what you wrote in your example. It's the same as C, except there are restrictions on the types that can be in the unions (IIRC they must have a default constructor). Here's the relevant Wikipedia article.
With C++11 you have anonymous unions and structs which just export their definitions to the enclosing scope, so you can do this:
typedef int Scalar;
struct Vector
{
union
{
struct
{
Scalar x, y;
};
Scalar v[2];
};
};