penso che le altre risposte sorta di mancato il punto della questione:
desidero accedere ai membri allo stesso modo come si farebbe con questo.
In altre parole, la questione è davvero "come faccio io definire un tipo vec
in modo conforme agli standard in modo tale che in un oggetto u
di quel tipo, u.x
, u.r
e u.elements[0]
si riferiscono tutti alla stessa cosa ?"
Bene, se insiste su quella sintassi ... allora la risposta ovvia è: riferimenti.
Quindi:
template <typename some_type>
struct vec
{
vec() = default;
vec(const vec& other) : elements{ other.elements[0], other.elements[1], other.elements[2] } {}
vec & operator=(const vec &other) {
elements[0] = other.elements[0];
elements[1] = other.elements[1];
elements[2] = other.elements[2];
return *this;
}
some_type elements[3];
some_type &x = elements[0], &y = elements[1], &z = elements[2];
some_type &r = elements[0], &g = elements[1], &b = elements[2];
};
Il primo problema di questo approccio è che avete bisogno di spazio extra per 6 membri di riferimento - che è piuttosto costoso per un piccolo struct tale.
Il secondo problema di questo approccio è che, data const vec<double> v;
, v.x
è ancora di tipo double &
, quindi si potrebbe scrivere v.x = 20;
e farlo compilare senza preavviso o errori - solo per ottenere un comportamento indefinito. Piuttosto male.
Così, in subordine, si potrebbe considerare l'utilizzo di funzioni di accesso:
template <typename some_type>
struct vec
{
some_type elements[3];
some_type &x() { return elements[0]; }
const some_type &x() const { return elements[0]; }
some_type &y() { return elements[1]; }
const some_type &y() const { return elements[1]; }
some_type &z() { return elements[2]; }
const some_type &z() const { return elements[2]; }
some_type &r() { return elements[0]; }
const some_type &r() const { return elements[0]; }
some_type &g() { return elements[1]; }
const some_type &g() const { return elements[1]; }
some_type &b() { return elements[2]; }
const some_type &b() const { return elements[2]; }
};
Si dovrebbe scrivere u.x()
ecc invece di u.x
, ma il risparmio di spazio è notevole, si può anche fare affidamento sul compilatore funzioni generiche di membri speciali, è banalmente copiabile se some_type
è (che abilita alcune ottimizzazioni), è un aggregato e quindi può utilizzare la sintassi di inizializzazione aggregata ed è anche const-correct.
Demo. Si noti che sizeof(vec<double>)
è 72 per la prima versione e solo 24 per la seconda.
Se si insiste sulla possibilità di scrivere 'vec t; t.x = 10; 'allora puoi dargli dei membri di riferimento' x', 'y',' z' ecc. e inizializzarli per fare riferimento al membro corrispondente di 'elements', ma questo aumenterà considerevolmente le dimensioni della struttura. Se è possibile tollerare 't.x() = 10', quindi renderli funzioni membro. –
Ma penso che 'vec.x = 42; assert (vec.r == 42); 'comunque non è la garanzia dello standard (ma il compilatore può). – Jarod42
@ Jarod42 N3936 [class.mem]/18: "Se un unione di layout standard contiene due o più strutture di layout standard che condividono una sequenza iniziale comune, e se l'oggetto unione layout standard contiene attualmente uno di questi standard- strutture di layout, è consentito per ispezionare la parte iniziale comune di ognuna di esse ... " – Casey