I have a struct that represents a vertex. It has x, y and z fields as well as several others. Recently I came into conclusion that for certain functionality I will need to access the coordinates of the vertex as an array. I didn't want to "pollute" the code with temporary variables or change all places that look like this v.y to this v.coord[1] which is not nice nor elegant. So I thought about using a union. Something like this should work:
struct {
float x,y,z;
} Point;
struct {
union {
float coord[3];
Point p;
};
} Vertex;
This is good, but not perfect. The point class has no point being there. I want to be able to access y coordinate simply by typing v.y (and not v.p.y).
Can you suggest a hack to solve this (or tell me that it is not possible)?
A good C++ approach is to use named accessors that return references to the elements:
class Point {
public:
float& operator[](int x) { assert(x <= 2); return coords_[x]; }
float operator[](int x) const { assert(x <= 2); return coords_[x]; }
float& X() { return coords_[0]; }
float X() const { return coords_[0]; }
float& Y() { return coords_[1]; }
float Y() const { return coords_[1]; }
float& Z() { return coords_[2]; }
float Z() const { return coords_[2]; }
private:
float coords_[3];
};
With this approach, given a Point p;, you can use both p[0] and p.X() to access the initial element of the internal coords_ array.
OK, this should work for you
struct {
union {
float coord[3];
struct
{
float x,y,z;
};
};
} Vertex;
What this code does is that it unions the array with the structure, so they share the same memory. Since the structure doesn't contain a name, it is accessible without a name, just like the union itself.
Related
I have a class Particle:
class Particle {
private:
float x, y, z;
// ...
public:
// ...
float* getPos() {
float p[3] = {x, y, z};
return p;
}
// ...
};
I would call this method like:
Particle a = Particle();
// ...
float* pos = a.getPos();
And then reference the position elements with pos[0] through pos[2].
g++ spouts warning message as stated in the title. But the functionality is exactly how I want it: returning an array. Why does the warning exist and is there a "proper" way to do it?
You can't return a C-array like that, return std::array instead:
std::array<float, 3> getPos() {
std::array<float, 3> p = {x, y, z};
return p;
}
You'll need to include <array> for that.
Personally, I'd skip std::array/std::vector here, because in your particular case, the position of each value imposes independent meaning. In general, sequence types have ordering, tuples have structure; if the element count is fixed (and often heterogeneous) and sorting (or otherwise reordering the values) is intrinsically nonsensical (e.g. in the case of a coordinate, swapping the x and y values changes the meaning), then a tuple makes more sense.
In this case, you could just declare:
std::tuple<float, float, float> getPos() {
// C++17 or higher allows list initialization
return {x, y, z};
// Pre-C++17 you use the std::make_tuple helper
return std::make_tuple(x, y, z);
}
The advantage here is that you can then unpack the result in the caller easily, either with std::tie:
float x, y, z;
std::tie(x, y, z) = a.getPos();
or on C++17 or higher with structured bindings, it's even nicer, since you can declare and initialize the variables with auto, rather than declaring with explicit types, then reassigning with tie:
auto [x, y, z] = a.getPos();
You can store the tuple itself and use std::get if you prefer, but unpacking to useful names rather than obscure std::get indices usually makes for much cleaner code.
You're not returning an array. It's impossible to return an array in C++. You're returning a pointer to an array which no longer exists. Hence the warning.
You could make the array a part of your class and return a pointer to that. In general I wouldn't call that good design
class Particle {
private:
float pos[3];
// ...
public:
// ...
float* getPos() {
return pos;
}
// ...
};
You could return a vector<float> instead. You could return an array<float,3> instead. You could ask yourself why you need this.
p[3] will be destroyed when it goes out of scope so you shouldn't return a pointer to it.
Either return a std::array<float, 3> by value or consider making a class for positions too, and return a Position object, or a reference to it. Example:
struct Position {
float x, y, z;
};
class Particle {
private:
Position m_pos;
// ...
public:
// ...
Position const& getPos() const { return m_pos; }
// ...
};
I'd suggest that you're function is indicative of poor design. Provide getter methods an allow the user of your class to access member variables:
class Particle {
private:
float x, y, z;
public:
float GetX() const { return x; }
float GetY() const { return y; }
float GetZ() const { return z; }
};
Given const Particle a this will let you initialize an array as follows: const float pos[] = { a.GetX(), a.GetY(), a.GetZ() }
Creating a Particle method to allow the user to populate a float[] will encourage the user toward one of the following bad practices:
float* Particle::GetPos() const { return new[3]{ x, y, z }; } creates dynamic memory without clearly informing the caller that the memory needs to be released
array<float, 3U> Particle::GetPos() const { return { x, y, z }; } requires the allocation and creation of a temporary to populate a float[]
void Particle::GetPos(float* param) const { param[0] = x; param[1] = y; param[2] = z; } misses the opportunity for constant arrays and incurs potential caller misuse, as it's not clear that param must have room for at least 3 floats
I have this code:
class Vector3
{
public:
Vector3() : x(values[0]), y(values[1]), z(values[2])
{ x = y = z = 0; }
float& x;
float& y;
float& z;
private:
float[3] values;
};
class Model
{
public:
Vector3 vertices[64];
};
I'm doing this vector class because I want to deal with the values as X, Y, Z in the code, but for some operations I need a contiguous array of values to be passed to a function.
So the whole array of vertices[64] need to be [x0][y0][z0][x1][y1][z1][x2][y2][z2] etc.
But if I do this:
//Get first address:
void* firstAddress = &vertices[0];
//Or
void* firstAddress = vertices;
I don't have the contiguous array as I need it (the data is all messed up), and I'm guessing it's because of the pointers I have in the Vector3 class.
Is there any way I can do get this functionality that I want? (Having a single array of float but dealing with values as x,y,z)
Firstly, the Standard doesn't define how references should be implemented, but they'll almost certainly occupy actual memory in your class much a pointer members would, ruining the contiguous data packing you're hoping for....
If your focus is more on the vertices container, and you just want x/y/z member access to elements in it, then you could try something like:
template <size_t N>
class Vertices
{
public:
class Proxy
{
public:
Proxy(float* p) : x(p[0]), y(p[1]), z(p[2]) { }
float& x;
float& y;
float& z;
};
Proxy operator[](size_t n) { return Proxy(&d_[n * 3]); }
const Proxy operator[](size_t n) const { return Proxy(&d_[n * 3]); }
private:
float d_[N * 3];
};
You could have member functions instead:
class V3
{
float data[3];
public:
V3() : data{0,0,0} {}
float & x() { return data[0]; }
float & y() { return data[1]; }
float & z() { return data[2]; }
};
You could also omit the constructor and have an aggregate, if that's more suitable.
What you have and array of values pointers (pointing to arrays of 3 floats) with 3 float references (x, y, z). You probably ant something more like:
float & x() { return values[0]; }
float & y() { return values[1]; }
float & z() { return values[2]; }
If I understand your requirement for continuous data in the Model, then your Vector is really an alias to a specific triple of data in the model. No float storage required.
class Model
class Vector
Vector(Model *model_, size_t idx_) : model(model_),idx(idx_) { };
Model *model;
size_t idx;
float & x() { return model->data[3*idx]; }
float & y() { return model->data[3*idx+1]; }
float & z() { return model->data[3*idx+2]; }
float data[64 * 3];
Vector vectors[64];
Model() {
...
for( size_t ii = 0; ii < 64; ii++ ) {
vectors[ii] = new Vector(this,ii);
}
Vector & vector(size_t idx) { return vectors[ii]; }
For a guaranteed contiguous array you need to either copy the data into the array, or use compiler-specific guarantees about memory layout, in particular that
there will be no padding,
and if you want to also access triplets of the array as Vector3 instances, that
accessing a Vector3 at arbitrary address will not cause a trap or inefficiency (we're into alignment here).
It so happens that some common libraries such as OpenCV do make such assumptions for their internal image buffers.
But I'm not entirely sure that the code I've seen has not been platform-adapted. So, in practice you have these choices:
copy the data contiguously to an array (or from it), and/or
use an existing library that provides this kind of functionality, such as OpenCV.
Note that using member functions instead of references buys you nothing wrt. to the contiguous array problem, but it does make the Vector3 potentially assignable.
On further reflection, i was maybe too trigger-happy writing the above. For if you can guarantee total size 3*sizeof(float), and that's almost a given (just get rid of those references), then you are guaranteed that you can access a Vector3 at any address that can hold a float, since C++ guarantees arrays with no padding, and since in such an array a Vector3 can end up at any address that can hold a float. So the in-practice problem reduces to making a decision about supporting compilers or compiler configurations that are unable to make Vector3 of size 3*sizeof(float).
I.e.
struct Vector3
{
float x, y, z;
auto operator[]( int i ) -> float& { return (&x)[i]; }
auto operator[]( int i ) const -> float const& { return (&x)[i]; }
};
static_assert( sizeof( Vector3 ) == 3*sizeof( float ), "Ungood Vector3 size" );
using the fact that members with no intervening access specifier are guaranteed to be in increasing address order.
Disclaimer: off the cuff code, not touched by compiler's hands.
If you keep your Vector3 class a POD you should be able to simply cast your vertices to a float array:
struct Vector3 {
float x;
float y;
float z;
};
class Model
{
public:
Vector3 vertices[64];
float* data() {
return reinterpret_cast<float*>(vertices);
}
};
int main() {
Model m;
for(int i = 0; i < 64; ++i) {
m.vertices[i] = {10+i,100+i,1000+i};
}
float *data = m.data();
for(int i= 0; i < 64*3; ++i) {
std::cout << data[i] << ", ";
}
}
Only problem could be the Allignment of the structure, but should you use c++11, there is a standard way of alligning the structure, using allignasalignas(alignof(float[3])). I don't know if this is really required.
Also, c++11 gives quite a few options on what to do with Vector3, while still considering it as a POD type.
Before anyone says anything I know this is probably not recommended but I am still curious if there is a better way to do it or reasons not to beyond just it's a strange thing to do.
I started looking into this because I wanted to access elements of an array directly with semantically named members in the class while still being able to iterate over the array and not have to call/create some getter or setter methods.
I have a class definition that looks something like this.
class Vertex{
public:
Vertex(float x,float y,float z,float w);
float v[4];
float &x,&y,&Z,&w;
};
And a constructor that looks like this. My question is. Is there a better way of doing what I am doing in the constructor?
Vertex::Vertex(float vx,float vy,float vz,float vw):
x(*const_cast<float*>( &this->v[0] )),
y(*const_cast<float*>( &this->v[1] )),
z(*const_cast<float*>( &this->v[2] )),
w(*const_cast<float*>( &this->v[3] ))
{
v[0]=vx;
v[1]=vy;
v[2]=vz;
v[3]=vw;
}
EDIT
I'm an idiot... you can just do it like Jonathan Wakely said.
x(v[0])
I guess I had some other problems before when I tried it. Oh well.
Vertex::Vertex(float vx,float vy,float vz,float vw):
v { vx, vy, vz, vw },
x(v[0]),
y(v[1]),
z(v[2]),
w(v[3])
{
}
I'd avoid writing reference members here. The reason is that reference members prevent defaulted (compiler generated) copy/assignment special members.
class Vertex{
public:
Vertex(float x,float y,float z,float w)
: v { x, y, z, w } { }
float &x() { return v[0]; }
float &y() { return v[1]; }
float &z() { return v[2]; }
float &w() { return v[3]; }
float const &x() const { return v[0]; }
float const &y() const { return v[1]; }
float const &z() const { return v[2]; }
float const &w() const { return v[3]; }
private:
float v[4];
};
You could go this way too:
class Vertex
{
public:
float x;
float y;
float z;
float w;
Vertex(float x, float y, float z, float w);
float&
operator[](int i)
{ return *(&x + i); }
float
operator[](int i) const
{ return *(&x + i); }
};
Probably, this variant is better (compared to other alternatives) because it requires less code and gives you the additional ability to iterate over Vertex in array-style.
Personally I like #sehe's answer best but I'll give you an alternative.
struct Vector4 {
float x;
float y;
float z;
float w;
};
union VectorUnion {
Vector4 vector;
float array[4];
};
Then you can just use the VectorUnion inside your Vertex class or on its own...
I am concerned about the fact that this is a C construct and that C++ struct is slightly different (it includes the vtable etc) but I think that it should work.
Again, I think #sehe's answer is better.
Is it possible in C++ to refer to the same variable using different names without using the preprocessor?
To achieve the same effect as this pseudocode
struct vec3f {
float[3] values;
};
struct color : public vec3f {
#define r values[0]
#define g values[1]
#define b values[2]
};
color c;
c.r = 0.5f;
The following has the right semantics except it allocates space in the struct for the 3 references:
struct color : public vec3f {
float& r;
float& g;
float& b;
color() : r(values[0]), g(values[1]), b(values[2]) { }
};
Is there a way to get this compile-time name substitution without increasing the size of the struct?
How about this?
struct vec3f {
float[3] values;
};
struct color : public vec3f
{
float& r() { return values[0]; }
float& g() { return values[1]; }
float& b() { return values[2]; }
const float& r() const { return values[0]; }
const float& g() const { return values[1]; }
const float& b() const { return values[2]; }
};
I am not sure that you want to use inheritance in this case. You might be better of with a plain old union type:
typedef float vec3f[3];
union color {
vec3f values;
struct {
float r;
float g;
float b;
};
};
color c;
c.values[0] = 10;
assert( c.r == 10 );
As it happens, I first saw a really neat trick for this several years ago.
The idea is that you give the class named variables in order, and then also have a static const member of array-of-pointer-to-member type. The operator[] is overloaded to look up the appropriate pointer-to-member, use it to select the member from this, and return a reference.
This works because pointer-to-members are not ordinary pointers; they're a little more magical than that. (This is what enables you to create un-bound pointers to member functions, and why they can't be used where plain function pointers are expected).
It also means that you don't have to use any casting tricks, rely on any kinds of alignment, non-portable anonymous-union behaviour, or memory layout guarantees, and you still get to refer to the components of the structure as named fields instead of via accessor functions.
ALTERNATIVE 1
You always create a temporary when you want a variable alias. With a good optimizer you will hardly see any performance difference.
struct vec3f
{
float values[3];
};
struct tempvec
{
float &r;
float &g;
float &b;
tempvec( vec3f& bar )
:r(bar.values[0])
, g(bar.values[1])
, b(bar.values[2]){}
};
int main()
{
vec3f temp;
temp.values[0] = 2.40f;
//when you want to alias values[0] as r do this
tempvec(temp).r = 42;
tempvec(temp).g = 42;
return 0;
}
ALTERNATIVE 2
If you can verify that memory layout of vec3f and vec3c is the same on your platform and OS.. taking into account padding/alignment etc... you can do
struct vec3f
{
float values[3];
};
struct vec3c
{
float r,g,b;
};
int main()
{
vec3f temp;
temp.values[0] = 2.40f;
vec3c* alias = reinterpret_cast<vec3c*>(&temp);
alias->r = 4.2f;
alias->g = 4.2f;
alias->b = 4.2f;
return 0;
}
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];
};
};