myślę pozostałe odpowiedzi jakby brakowało punkt pytanie:
życzę, aby uzyskać dostęp członków w taki sam sposób jak w przypadku tego produktu.
Innymi słowy, pytanie jest naprawdę „jak mogę określić typ vec
w standardowym zgodny taki sposób, że dany obiekt u
tego typu, u.x
, u.r
i u.elements[0]
wszystkie odnoszą się do tego samego ? "
Cóż, jeśli nalegasz na tę składnię ... wtedy oczywista odpowiedź brzmi: referencje.
Więc:
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];
};
Pierwszym problemem z tego podejścia jest to, że potrzebne są dodatkowe miejsca dla 6 członków odniesienia - co jest dość drogie jak na taki mały struktury.
Drugi problem z tego podejścia jest to, że biorąc pod uwagę const vec<double> v;
, v.x
jest nadal typu double &
, więc można napisać v.x = 20;
i mieć go skompilować bez ostrzeżenia lub błędu - tylko dostać niezdefiniowane zachowanie. Dość źle.
Tak, alternatywnie, można rozważyć użycie funkcje dostępowe:
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]; }
};
Trzeba by napisać u.x()
itd zamiast u.x
, ale oszczędności przestrzeni jest znaczna, można również liczyć na kompilatora Generowane funkcje specjalne, to trywialnie kopiowalna, jeśli jest to some_type
(co umożliwia pewne optymalizacje), jest agregatem i może używać składni inicjującej agregację, a także jest poprawna.
Demo. Zauważ, że sizeof(vec<double>)
to 72 dla pierwszej wersji i tylko 24 dla drugiej.
Jeśli nalegasz na możliwość napisania 'vec t; t.x = 10; 'następnie możesz nadać elementom referencyjnym' x', 'y',' z' itd. i zainicjować je tak, aby odnosiły się do odpowiedniego elementu 'elements', ale zwiększy to znacznie rozmiar struktury. Jeśli możesz tolerować 't.x() = 10', a następnie uczynić je funkcjami składowymi. –
Ale myślę, że 'vec.x = 42; assert (vec.r == 42); 'i tak nie jest gwarantowane przez standard (ale może to być kompilator). – Jarod42
@ Jarod42 N3936 [class.mem]/18: "Jeśli ujednolicony układ zawiera dwa lub więcej struktur o standardowym układzie, które mają wspólną początkową sekwencję, i jeśli standardowy obiekt złożenia zawiera obecnie jeden z tych standardów: układ struktur, jest dozwolone do sprawdzenia wspólnej początkowej części któregokolwiek z nich. ... " – Casey