Reputation: 629
What is the meaning of having some fields inside a struct inside a union in C++? I found this from a piece of code from the "Math for game developers" video series in YouTube:
private:
union {
struct {
float m_x,m_Y;
};
};
Upvotes: 2
Views: 250
Reputation: 25449
I have checked out revision 2d964cbb9e5065ec327ef6e2a5f086820ed024c1
and grep
ped for union
and the closest match to your code sample I could find was in math/vector.h
following line 56.
Cut down to the construct in question, we basically have this. (Note that this is different from the code you are showing.)
struct vec3
{
union
{
struct
{
float x;
float y;
float z;
};
float v[3];
};
};
This will allow us to refer to the elements of a vec3
either by name, as in
std::ostream&
operator<<(std::ostream& os, const vec3& v3)
{
os << "(" << v3.x << ", " << v3.y << ", " << v3.z << ")";
return os;
}
or using array syntax as in
std::ostream&
operator<<(std::ostream& os, const vec3& v3)
{
os << "(";
for (std::size_t i = 0; i < 3; ++i)
os << (i ? ", " : "") << v3.v[i];
os << ")";
return os;
}
While this is about as good as you can get in C, personally, I think this is poor style C++. A more modern cleaner and equally efficient approach would use inline accessor functions and overload operator[]
.
#include <cstddef>
#include <stdexcept>
#ifndef NDEBUG
# define DEBUG 1
#else
# define DEBUG 0
#endif
class vec3
{
private:
float data_[3];
public:
constexpr vec3() noexcept : data_ {0.0f, 0.0f, 0.0f}
{
}
constexpr vec3(const float x, const float y, const float z) noexcept : data_ {x, y, z}
{
}
const float& x() const noexcept { return this->data_[0]; }
const float& y() const noexcept { return this->data_[1]; }
const float& z() const noexcept { return this->data_[2]; }
float& x() noexcept { return this->data_[0]; }
float& y() noexcept { return this->data_[1]; }
float& z() noexcept { return this->data_[2]; }
const float&
operator[](const std::size_t i) const noexcept(!DEBUG)
{
if (DEBUG && i >= 3)
throw std::invalid_argument {"vector index out of range"};
return this->data_[i];
}
float&
operator[](const std::size_t i) noexcept(!DEBUG)
{
if (DEBUG && i >= 3)
throw std::invalid_argument {"vector index out of range"};
return this->data_[i];
}
};
While this is arguably a little redundant, it will pay off by giving us a very clean and efficient interface.
Using explicit member access:
std::ostream&
operator<<(std::ostream& os, const vec3& v3)
{
os << "(" << v3.x() << ", " << v3.y() << ", " << v3.z() << ")";
return os;
}
Using array syntax (optionally range-checked):
std::ostream&
operator<<(std::ostream& os, const vec3& v3)
{
os << "(";
for (std::size_t i = 0; i < 3; ++i)
os << (i ? ", " : "") << v3[i];
os << ")";
return os;
}
Upvotes: 1