2016-06-19 7 views
0

Ich habe die folgenden zwei Gewerkschaften:Rund Cast-Operatoren zwischen zwei Gewerkschaften

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

Ich möchte operator hsv_color()-rgb_colorunion hinzuzufügen, und operator rgb_color()-hsv_colorunion. Gibt es einen Weg, es zu tun? Wenn ich hsv_color voraus erklären, führt der Compiler den folgenden Fehler:

error: return type 'union hsv_color' is incomplete 

Je mehr ich versuche, dies zu implementieren, desto mehr ich denke, ich sollte nur für die Konvertierung zwei Funktionen erstellen, anstatt mit impliziten Besetzung Betreiber. Dennoch würde ich gerne wissen, ob das möglich ist. Irgendwelche Vorschläge?

+2

Ich hoffe, dass Sie nicht mit diesen Gewerkschaften Typ-Puning tun: zum Beispiel das Schreiben in die 'raw' und dann von' Farbton lesen 'und umgekehrt ist UB –

+0

@Revolver_Ocelot: Wenn du bei UB undefiniertes Verhalten meinst, dann verdammt, wusste das nicht! Ist das nur in C++ oder auch in C? – xx77aBs

+1

das ist, wie Gewerkschaften arbeiten, wenn Sie "roh" und "Farbton" zur gleichen Zeit brauchen, vielleicht sollte es nicht eine Union in erster Linie sein – user463035818

Antwort

2

Ich würde vorschlagen, den Code unten, aber Ihre grundlegende Annahme, dass Struktur von 3 Floats wird genau den gleichen Speicher wie Array von 3 Floats ist wahrscheinlich falsch. Es gibt Strukturelementausrichtung. Sie müssen eine "Pragma Pack" -Richtlinie verwenden. Lese here zum Beispiel

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

Ich würde eine Art-punning Vereinigung vermeiden, da es UB unter der strengen Aliasing-Regel wird.

Ich nehme an, dass Sie ein Array einbeziehen, weil Sie dieses Array an eine API wie opengl übergeben müssen.

In diesem Fall würde ich einfach das Array verwenden und Accessoren Zugriff auf r, g, b, h, s und v semantisch.

können Sie die notwendige Konvertierungskonstruktor mit einer zukunfts Erklärung:

// 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 */ }