Consider this:
class Vec3
{
private:
float n[3];
public:
float& x;
float& y;
float& z;
Vec3(float x_, float y_, float z_) : x(n[0]), y(n[1]), z(n[2])
{
x = x_;
y = y_;
z = z_;
}
}
can I be sure that doing this:
Vec3 v(1,2,3);
cout<<reinterpret_cast<float*>(&v)[0]<<"\t";
cout<<reinterpret_cast<float*>(&v)[1]<<"\t";
cout<<reinterpret_cast<float*>(&v)[2]<<"\t";
will give me 1 2 3 by every compiler/OS that follows the standard?
No. For that to work, you'd need (at least) a standard-layout type. float& isn't, and therefore Vec3 isn't either. (9/7, first bullet).
As said in other answers, this won't work, because of the float&. See Standard Layout Classes and Trivially Copyable Types for a long explanation about standard layout.
You could consider a slightly different approach:
class Vec3
{
private:
float n[3];
public:
float& x() { return n[0]; }
float& y() { return n[1]; }
float& z() { return n[2]; }
Vec3(float x_, float y_, float z_)
{
x() = x_;
y() = y_;
z() = z_;
}
};
Thus,
Vec3 v(1,2,3);
cout<<reinterpret_cast<float*>(&v)[0]<<"\t";
cout<<reinterpret_cast<float*>(&v)[1]<<"\t";
cout<<reinterpret_cast<float*>(&v)[2]<<"\t";
Will print 1 2 3 for all compilers
Edit
You might also want to see What are Aggregates and PODs (1st answer) and What are Aggregates and PODs (2nd answer) for more precise information.
Nope. Your class is not POD, so there are no guarantees whatsoever, AFAIK.
Related
Due to some legacy C code, I have the following POD struct defining 2D coordinates; and a C++ class inheriting from it in order to provide various operations:
struct coord
{
double x;
double y;
};
class CoordClass : public coord
{
// Contains functions like...
const CoordClass& operator+=(const CoordClass& rhs)
{
x += rhs.x;
y += rhs.y;
return *this;
}
double Magnitude() const { return std::sqrt(x*x + y*y); }
};
At present, CoordClass defines a constructor:
CoordClass(double xx, double yy) { x = xx; y = yy; }
Given x and y are members of the POD base struct coord, is it possible to write that constructor as an initialiser list and empty body instead? Answers considering both C++03 and C++11 interest me.
In C++11 you can provide this constructor:
CoordClass(double x, double y) : coord{x, y} {}
In C++03 is also possible to get an empty constructor body but I don't think it's worth doing:
CoordClass(double x, double y) : coord(make_coord(x, y)) {}
where make_coord is:
coord make_coord(double x, double y) {
coord c = { x, y };
return c;
}
It can be a private static method of CoordClass. Alternatively, it can be a free function which is static and/or a member of an anonymous namespace of CoordClass.cpp.
In C++11, if you define a defaulted default constructor to a struct, it can still be a POD in C++11. (See Is this struct POD in C++11? )
struct coord
{
double x;
double y;
coord() = default;
coord(double xx, double yy) : x(xx), y(yy) {}
};
Now the CoordClass constructor becomes easy:
CoordClass(double x, double y) : coord(x, y) {}
Try the following
CoordClass(double xx, double yy) : coord { xx, yy } {}
I could find a way to do Designated Initializers in C++0x with only one member initializing.
Is there a way for multiple member initializing ?
public struct Point3D
{
Point3D(float x,y) : X_(x) {}
float X;
};
I want :
public struct Point3D
{
Point3D(float x,y,z) : X_(x), Y_(y), Z_(z) {}
float X_,Y_,Z_;
};
You have a few mistakes in your constructor, here is how you should write it:
/* public */ struct Point3D
// ^^^^^^
// Remove this if you are writing native C++ code!
{
Point3D(float x, float y, float z) : X_(x), Y_(y), Z_(z) {}
// ^^^^^ ^^^^^
// You should specify a type for each argument individually
float X_;
float Y_;
float Z_;
};
Notice, that the public keyword in native C++ has a meaning which is different from the one you probably expect. Just remove that.
Moreover, initialization lists (what you mistakenly call "Designated Initializers") are not a new feature of C++11, they have always been present in C++.
#Andy explained how you should be doing this if you're going to define your own struct.
However, there is an alternative:
#include <tuple>
typedef std::tuple<float, float, float> Point3D;
and then define some function as:
//non-const version
float& x(Point3D & p) { return std::get<0>(p); }
float& y(Point3D & p) { return std::get<1>(p); }
float& z(Point3D & p) { return std::get<2>(p); }
//const-version
float const& x(Point3D const & p) { return std::get<0>(p); }
float const& y(Point3D const & p) { return std::get<1>(p); }
float const& z(Point3D const & p) { return std::get<2>(p); }
Done!
Now you would use it as:
Point3D p {1,2,3};
x(p) = 10; // changing the x component of p!
z(p) = 10; // changing the z component of p!
Means instead of p.x, you write x(p).
Hope that gives you some starting point as to how to reuse existing code.
So I have a vec4 class that uses members x,y,z,w which you can access using
point.x point.y etc.
However I want to reuse this vec4 class to be my color class (it already supports scalar multiplication, operator overloading lots of other nice stuff)
I just want to be able to refer to the members using another notation:
color.r
color.g
color.b
etc.
Is there anyway I can do this using a macro or other syntactic sugar?
If you are using Visual Studio (and are sure that it is the only target IDE...) you can use the following:
#include <cassert>
union vec4
{
struct
{
float x;
float y;
float z;
float w;
};
struct
{
float r;
float g;
float b;
float a;
};
};
int main()
{
vec4 vec = { 0 };
vec.y = 10.0f;
assert(vec.g == 10.0f);
return 0;
}
It will yield warnings warning C4201: nonstandard extension used : nameless struct/union, though you can disable it.
EDIT: as it turns out gcc supports this extension as well.
Unless you have a good amount of common behavior between a vector and a color I think this is a bad idea. But since you asked, here is a possible way to do that.
If you make the x, y, z and w members private and provide accessor methods to get to them, then it is easy to provide two alternative ways to refer to the same member variables. For example:
class vec4 {
private:
float _x, _y, _z, _w;
public:
// vector getter/setters
float& x() { return _x; }
float& y() { return _y; }
float& z() { return _z; }
float& w() { return _w; }
// color getter/setters
float& r() { return _x; }
float& g() { return _y; }
float& b() { return _z; }
float& a() { return _w; }
};
vec4 my_color;
my_color.r() = 1.0f;
my_color.g() = 0.0f;
my_color.b() = 0.0f;
my_color.a() = 1.0f;
You can easily do that with standalone accessor functions:
struct vec4 { double x, y, z; };
double& get_r(vec4& v) { return v.z; }
// and so on
I've got two classes: a template class, and a regular class that inherits from it:
template <int N> class Vector
{
float data[N];
//etc. (math, mostly)
};
class Vector3 : public Vector<3>
{
//Vector3-specific stuff, like the cross product
};
Now, I'd like to have x/y/z member variables in the child class (full members, not just getters - I want to be able to set them as well). But to make sure that all the (inherited) math works out, x would have to refer to the same memory as data[0], y to data[1], etc. Essentially, I want a union, but I can't declare one in the base class because I don't know the number of floats in the vector at that point.
So - can this be done? Is there some sort of preprocessor / typedef / template magic that will achieve what I'm looking for?
PS: I'm using g++ 4.6.0 with -std=c++0x, if that helps.
Edit: While references would give the syntax I'm looking for, the ideal solution wouldn't make the class any bigger (And references do - a lot! A Vector<3> is 12 bytes. A Vector3 with references is 40!).
How about:
class Vector3 : public Vector<3>
{
public:
// initialize the references...
Vector3() : x(data[0]), y(data[1]), z(data[2]){}
private:
float& x;
float& y;
float& z;
};
Of course, if you want them to occupy the same space, then that's a different story...
With a little template magic, you can do the following...
#include <iostream>
template <int N, typename UnionType = void*> struct Vector
{
union
{
float data[N];
UnionType field;
};
void set(int i, float f)
{
data[i] = f;
}
// in here, now work with data
void print()
{
for(int i = 0; i < N; ++i)
std::cout << i << ":" << data[i] << std::endl;
}
};
// Define a structure of three floats
struct Float3
{
float x;
float y;
float z;
};
struct Vector3 : public Vector<3, Float3>
{
};
int main(void)
{
Vector<2> v1;
v1.set(0, 0.1);
v1.set(1, 0.2);
v1.print();
Vector3 v2;
v2.field.x = 0.2;
v2.field.y = 0.3;
v2.field.z = 0.4;
v2.print();
}
EDIT: Having read the comment, I realise what I posted before was really no different, so a slight tweak to the previous iteration to provide direct access to the field (which is what I guess you are after) - I guess the difference between this and Rob's solution below is that you don't need all the specializations to implement all the logic again and again...
How about template specialization?
template <int N> class Vector
{
public:
float data[N];
};
template <>
class Vector<1>
{
public:
union {
float data[1];
struct {
float x;
};
};
};
template <>
class Vector<2>
{
public:
union {
float data[2];
struct {
float x, y;
};
};
};
template <>
class Vector<3>
{
public:
union {
float data[3];
struct {
float x, y, z;
};
};
};
class Vector3 : public Vector<3>
{
};
int main() {
Vector3 v3;
v3.x;
v3.data[1];
};
EDIT Okay, here is a different approach, but it introduces an extra identifier.
template <int N> class Data
{
public:
float data[N];
};
template <> class Data<3>
{
public:
union {
float data[3];
struct {
float x, y, z;
};
};
};
template <int N> class Vector
{
public:
Data<N> data;
float sum() { }
float average() {}
float mean() {}
};
class Vector3 : public Vector<3>
{
};
int main() {
Vector3 v3;
v3.data.x = 0; // Note the extra "data".
v3.data.y = v3.data.data[0];
};
Here's one possibility, cribbed from my answer to this question:
class Vector3 : public Vector<3>
{
public:
float &x, &y, &z;
Vector3() : x(data[0]), y(data[1]), z(data[2]) { }
};
This has some problems, like requiring you to define your own copy constructor, assignment operator etc.
You can make the following:
template <int N> struct Vector
{
float data[N];
//etc. (math, mostly)
};
struct Vector3_n : Vector<3>
{
//Vector3-specific stuff, like the cross product
};
struct Vector3_a
{
float x, y, z;
};
union Vector3
{
Vector3_n n;
Vector3_a a;
};
Now:
Vector3 v;
v.n.CrossWhatEver();
std::cout << v.a.x << v.a.y << v.a.z
You could try the anonymous union trick, but that is not standard nor very portable.
But note that with this kind of union it is just too easy to fall into undefined behaviour without even noticing. It will probably mostly work anyway, though.
I wrote a way a while back (that also allowed getters/setters), but it was such a non-portable garrish hack that YOU REALLY SHOULD NOT DO THIS. But, I thought I'd throw it out anyway. Basically, it uses a special type with 0 data for each member. Then, that type's member functions grab the this pointer, calculate the position of the parent Vector3, and then use the Vector3s members to access the data. This hack works more or less like a reference, but takes no additional memory, has no reseating issues, and I'm pretty sure this is undefined behavior, so it can cause nasal demons.
class Vector3 : public Vector<3>
{
public:
struct xwrap {
operator float() const;
float& operator=(float b);
float& operator=(const xwrap) {}
}x;
struct ywrap {
operator float() const;
float& operator=(float b);
float& operator=(const ywrap) {}
}y;
struct zwrap {
operator float() const;
float& operator=(float b);
float& operator=(const zwrap) {}
}z;
//Vector3-specific stuff, like the cross product
};
#define parent(member) \
(*reinterpret_cast<Vector3*>(size_t(this)-offsetof(Vector3,member)))
Vector3::xwrap::operator float() const {
return parent(x)[0];
}
float& Vector3::xwrap::operator=(float b) {
return parent(x)[0] = b;
}
Vector3::ywrap::operator float() const {
return parent(y)[1];
}
float& Vector3::ywrap::operator=(float b) {
return parent(y)[1] = b;
}
Vector3::zwrap::operator float() const {
return parent(z)[2];
}
float& Vector3::zwrap::operator=(float b) {
return parent(z)[2] = b;
}
To finish off an old question: No. It makes me sad, but you can't do it.
You can get close. Things like:
Vector3.x() = 42;
or
Vector3.x(42);
or
Vector3.n.x = 42;
or even
Vector3.x = 42; //At the expense of almost quadrupling the size of Vector3!
are within reach (see the other answers - they're all very good). But my ideal
Vector3.x = 42; //In only 12 bytes...
just isn't doable. Not if you want to inherit all your functions from the base class.
In the end, the code in question ended up getting tweaked quite a bit - it's now strictly 4-member vectors (x, y, z, w), uses SSE for vector math, and has multiple geometry classes (Point, Vector, Scale, etc.), so inheriting core functions is no longer an option for type-correctness reasons. So it goes.
Hope this saves someone else a few days of frustrated searching!
I want to be able to create a type that has 3 floats (x,y,z). I have tried:
typedef struct
{
float x;
float y;
float z;
} Vertex;
But that didn't work.
Does this have to be declared somewhere where it can be seen by main? How would I go about creating getter methods and other methods for a type I have made?
How I'd do it in C++. See main() for example usage. N.B. This hasn't been compiled or tested.
#include <iostream>
class Vertex
{
public:
// Construction
Vertex(float x,float y, float z) : x_(x), y_(y), z_(z) {}
// Getters
float getX() const {return x_;}
float getY() const {return y_;}
float getZ() const {return z_;}
// Setters
void setX(float val) {x_ = val;}
void setY(float val) {y_ = val;}
void setZ(float val) {z_ = val;}
private:
float x_;
float y_;
float z_;
};
int main()
{
Vertex v(6.0f,7.2f,3.3f);
v.setZ(7.7f);
std::cout < "vertex components are " << v.getX() << ',' << v.getY() << ',' << v.getZ() << std::endl;
}
does this have to be declared somewhere where it can be seen by main?
Yes. Typically the class or struct is declared in a header file, which you #include in whatever translation unit (c file) you use it in.
Using C, this works for me
typedef struct { float x; float y; float z; } Vertex;
int main(void) {
Vertex a = {42, -42, 0};
if (a.x + a.y + a.z == 0) return 1; /* warning about comparing floating point values */
return 0;
}