Reputation: 4768
I have the following two unions:
union rgb_color
{
struct {
float red;
float green;
float blue;
};
float raw[3];
};
union hsv_color
{
struct {
float hue;
float saturation;
float value;
};
float raw[3];
}
I'd like to add operator hsv_color()
to rgb_color
union
, and operator rgb_color()
to hsv_color
union
. Is there a way to do it? If I forward-declare hsv_color
, the compiler throws the following error:
error: return type 'union hsv_color' is incomplete
The more I'm trying to implement this, the more I'm thinking I should just create two functions for conversion instead of using implicit cast operators. Still, I'd like to know if this is possible. Any suggestions?
Upvotes: 0
Views: 107
Reputation: 2214
I would suggest the code below, but your basic assumption that struct of 3 floats will take exactly the same memory as array of 3 floats is probably wrong. There is structure member alignment. You'll need to use some "pragma pack" directive. Read here for example
struct hsv_color;
struct rgb_color
{
union
{
struct
{
float red;
float green;
float blue;
}rgb;
float raw[3];
};
operator hsv_color();
};
struct hsv_color
{
union
{
struct
{
float hue;
float saturation;
float value;
} hsv;
float raw[3];
};
operator rgb_color();
};
rgb_color::operator hsv_color()
{
hsv_color ret;
// convert 'this' to hsv_color
ret.hsv.hue = 0;//todo: perform appropriate calculation here
ret.hsv.saturation = 0;//todo: perform appropriate calculation here
ret.hsv.value = 0;//todo: perform appropriate calculation here
return ret;
}
hsv_color::operator rgb_color ()
{
rgb_color ret;
// convert 'this' to rgb_color
ret.rgb.red = 0;//todo: perform appropriate calculation here
ret.rgb.green = 0;//todo: perform appropriate calculation here
ret.rgb.blue = 0;//todo: perform appropriate calculation here
return ret;
}
Upvotes: 2
Reputation: 69902
I would avoid a type-punning union as it becomes UB under the strict aliasing rule.
I take it that you are involving an array because you need to pass this array to an API, such as opengl.
In which case I would simply use the array and provide accessors to access r, g, b, h, s and v semantically.
You can provide the necessary conversion constructor with a forward-declaration:
// forward declare
struct hsv_color;
struct rgb_color
{
rgb_color(float r, float g, float b)
: raw { r, g, b }
{}
// forward declare
rgb_color(hsv_color);
float& r() { return raw[0]; }
const float& r() const { return raw[0]; }
float& g() { return raw[1]; }
const float& g() const { return raw[1]; }
float& b() { return raw[2]; }
const float& b() const { return raw[2]; }
const float* data() const { return raw; }
float* data() { return raw; }
private:
float raw[3];
};
struct hsv_color
{
hsv_color(float h, float s, float v)
: raw { h, s, v }
{}
hsv_color(rgb_color rgb) { /*conversion here*/ }
// more accessors here
float raw[3];
};
// define
rgb_color::rgb_color(hsv_color hsv) { /* implement here */ }
Upvotes: 1