Multiple names for the same variable in C++ - c++

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

Related

Struct with array that changes dynamically

I have been looking to change dynamically the values of an array in a struct depending on other variables of the struct.
Let's say I have:
struct foo
{
int value1 = 0;
int value2 = 0;
int arr[2] = {value1, value2};
};
In the main if I have create an instance fooInstance and I want to associate a value to value1 fooInstance.value1 = 10, how can I update the value in the array ?
Thank you for your time.
Firstly, if you need an array, then I recommend storing the objects in the array directly.
I question the value (i.e. usefulness) of these aliases such as value1 when the name has no more meaning than referring to arr[i] directly. But I can see the value in case there is a descriptive name available. I'll use a more meaningful example of 2D vector with x, y dimensions. It should be easy to change float to int and change the names to match your attempt.
While Frank's solution using functions is great in most regards, it has a small caveat of having a less convenient syntax compared to variables. It's possible to achieve the variable syntax using operator overloading and anonymous unions. The trade-off is the increased boilerplate in the class definition. Example:
union Vector2 {
struct {
float a[2];
auto& operator=(float f) { a[0] = f; return *this; }
operator float&() & { return a[0]; }
operator const float&() const & { return a[0]; }
operator float () && { return a[0]; }
float* operator&() { return &a[0]; }
} x;
struct {
float a[2];
auto& operator=(float f) { a[1] = f; return *this; }
operator float&() & { return a[1]; }
operator const float&() const & { return a[1]; }
operator float () && { return a[1]; }
float* operator&() { return &a[1]; }
} y;
struct {
float a[2];
auto& operator=(float f) { a[0] = a[1] = f; return *this; }
float* begin() { return std::begin(a); }
float* end() { return std::end(a); }
} xy;
};
int main() {
Vector2 v2;
v2.xy = 1337; // assign many elements by name
v2.x = 42; // assign one element by name
std::cout << v2.x; // read one element by name
for(float f : v2.xy) { // iterate the entire array
std::cout << f;
}
}
Note to those unfamiliar with rules of unions: Reading from inactive union member is allowed only through common initial sequence of standard layout structs. This code is well defined, but the reader should be careful to not over generalise and assume that type punning through unions would be allowed; It isn't.
I adapted code from my earlier answer to another question.
It is different parameters coming from different hardwares.
This sounds like generating the accessors shown above with meta programming could be a good approach.
But, if you would like to avoid the complexity, then a more traditional approach would be to just use the array, and use enum to name the indices:
struct foo
{
int arr[100];
enum indices {
name1,
name2,
// ...
name100,
name_count,
};
};
int main()
{
foo f;
f.arr[foo.name1] = 42;
}
If at all possible, use encapsulation. That's the preferred way to create an interface/implementation skew:
struct foo
{
int& value1() { return arr_[0]; }
int& value2() { return arr_[1]; }
int* arr() { return arr_; }
private:
int arr_[2] = {0, 0};
};
void bar(foo& v) {
// access a single value
v.value1() = 3;
// access the whole array
v.arr()[0] = 5;
}
If you need access through both the individual member variables and through an array member variable, do not copy the data; rather, use the array as "the source of truth", and provide access through the individual variables or the individual member functions.
Here is your example rewritten to "alias" array variables to scalar member variables:
struct foo
{
foo() : value1(arr[0]), value2(arr[1]) {}
std::array<int,2> arr;
int& value1;
int& value2;
};
Note: this is not a good way of doing anything in production code, just an illustration of how the language lets you do something like this. Normally I would add accessor member-functions instead of member-variable references, because it avoids many problems referenced in the comments, such as breaking the value semantics.

C++ How to treat an array of classes as an array of primary types?

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.

C++ mapping a variable address?

I have this class:
class Texture
{
public:
//I need this variable in this format
float diffuseColor[3];
}
But I'd like to make an easier interface than dealing with "diffuseColor[0]" and such, something like:
myTexture.color.r = 1.0f; //this is diffuseColor[0]
So I'm trying to get a class that works as a shell to the diffuseColor values, something like:
class Color
{
public:
float *r, *g, *b;
}
And in my Texture class:
class Texture
{
public:
Texture()
{
color.r = &diffuseColor[0];
color.g = &diffuseColor[1];
color.b = &diffuseColor[2];
}
Color color;
private:
float diffuseColor[3];
}
But the way it is now, I have to de-reference the color values if I want to use them:
(*myTexture.color.r) = 1.0f;
How can I achieve this without having to de-reference it everytime I want to use it?
You can use references which would be initialized in the member initializer list:
struct Color {
Color(float* colors): r(colors[0]), g(colors[1]), b(colors[2]) {}
float& r;
float& g;
float& b;
};
class Texture {
float diffuseColor[3];
public:
Color color;
Texture(): diffuseColor(), color(this->diffuseColor) {}
};
If you need to copy and/or assign Texture objects, you'll also need to implement a copy constructor and an assignment operator. Also note that this convenience has a relatively steep costs: both the pointers and the reference approach will increase the size of the Texture objects by 3 pointer. You might be better off to use accessors, instead, e.g.:
class Texture {
float diffuseColor[3];
public:
float& r() { return this->diffuseColor[0]; }
float& g() { return this->diffuseColor[1]; }
float& b() { return this->diffuseColor[2]; }
};
Maybe you can use the union language feature of C++:
union ColorUnion {
// first representation (Texture)
struct TextureColor {
float diffuseColor[3];
}
// second representation (RGB)
struct RGBColor {
float r;
float g;
float b;
}
};

Union hack needed

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.

C++ union array and vars?

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];
};
};