C ++ medlem variable aliaser?

stemmer
10

Jeg er ganske sikker på at dette er mulig, fordi jeg er ganske sikker på at jeg har sett det gjort. Jeg synes det er kjempebra, men jeg vil gjerne imot svar langs linjene av dette er en forferdelig idé fordi ____.

Si at vi har en grunnleggende struct.

struct vertex
{
    float x, y, z;
};

Nå ønsker jeg å gjennomføre aliaser på disse variablene.

vertex pos;
vertex col;
vertex arr;

pos.x = 0.0f; pos.y = 0.5f; pos.z = 1.0f;
col.r = 0.0f; col.g = 0.5f; col.b = 1.0f;
arr[0] = 0.0f; arr[1] = 0.5f; arr[2] = 1.0f;

Ideelt den tredje syntaksen ville være umulig å skille fra en matrise. Det vil si, hvis jeg sendes arrsom en referanse til parameter en funksjon forventer en rekke flottører inn i hvilken den vil lagre data (for eksempel mange av de OpenGL glGetfunksjoner), vil det fungere bra.

Hva tror du? Mulig? Mulig, men dum?

Publisert på 30/01/2009 klokken 05:50
kilden bruker
På andre språk...                            


12 svar

stemmer
21

Hva jeg kan gjøre er å accessors:

struct Vertex {
    float& r() { return values[0]; }
    float& g() { return values[1]; }
    float& b() { return values[2]; }

    float& x() { return values[0]; }
    float& y() { return values[1]; }
    float& z() { return values[2]; }

    float  operator [] (unsigned i) const { return this->values_[i]; }
    float& operator [] (unsigned i)       { return this->values_[i]; }
    operator float*() const { return this->values_; }

private:
    float[3] values_;
}
Svarte 30/01/2009 kl. 06:12
kilden bruker

stemmer
12

Bruk en union?

union vertex
{
    struct { float x, y, z; };
    struct { float r, g, b; };
    float arr[3];
};

Jeg vil ikke anbefale det - det vil føre til forvirring.


lagt :

Som det fremgår av Adrian i sitt svar, er denne foreningen med anonyme struct medlemmer som ikke støttes av ISO C ++. Det fungerer i GNU G ++ (med klager på ikke blir støttet når du slår på ' -Wall -ansi -pedantic'). Det minner om den pre-pre-standard C-dager (pre-K & R første EDN), når strukturen elementnavn måtte være unikt på tvers av alle strukturer, og du kan bruke kontrakt notasjoner for å få til en forskyvning i strukturen, og du kan bruke medlemsnavn fra andre strukturtyper - en form for anarki. Da jeg begynte å bruke C (for lenge siden, men etter K & R1), som allerede var historisk bruk.

Notasjonen vist med anonyme fagforeningsmedlemmer (for de to strukturene) er støttet av C11 (ISO / IEC 9899: 2011), men ikke av tidligere versjoner av C-standarden. Avsnitt 9.5 i ISO / IEC 14882: 2011 (C ++ 11) gir for anonyme fagforeninger, men GNU g++(4.9.1) godtar ikke koden vist med -pedantic, identifisere " warning: ISO C++ prohibits anonymous structs [-Wpedantic]".

Siden ideen vil føre til forvirring, jeg er ikke spesielt bekymret for at det ikke er standard; Jeg ville ikke bruke mekanismen for denne oppgaven (og jeg ville være skeptisk til å bruke anonyme strukturer i en union, selv om det var gunstig).


En bekymring ble reist:

De tre (xyz, RGB og matrisen) ikke nødvendigvis linje med hverandre.

Det er en forening med tre elementer; de tre elementene starter på samme adresse. De to første er strukturer som inneholder 3 flyte verdier. Det er ingen arv og det er ingen virtuelle funksjoner for å gi forskjellige utforminger, etc. Konstruksjonene vil bli lagt ut sammen med de tre elementene sammenhengende med (i praksis, selv om standarden tillater padding). Matrisen også starter på samme adresse, og i henhold til "no polstring i strukturene, de elementene overlapper de to strukturer. Jeg virkelig ikke se at det skulle være et problem.

Svarte 30/01/2009 kl. 05:59
kilden bruker

stemmer
10

Navnløse nestede structs i en union er ikke standard C ++. Dette, derimot, bør arbeide:

struct Vertex
{
private:
   typedef float Vertex::* const vert[3];
   static const vert v;

public:
   typedef size_t size_type;
   float x, y, z;

   const float& operator[](size_type i) const {
      return this->*v[i];
   }

   float& operator[](size_type i) {
      return this->*v[i];
   }

};

const Vertex::vert Vertex::v = {&Vertex::x, &Vertex::y, &Vertex::z};

EDIT: Litt mer informasjon. Struct anvender en matrise av 3 peker-til-data organene for å få tilgang til dataene i de overbelastede [] operatører.

Linjen "typedef flyte Vertex :: * const vert" betyr at vert er en peker til et oppdriftselement av Vertex struct. Den [3] betyr at det er en rekke av tre av disse. I belastet operatøren [], er denne matrise indeksert og pekeren-til-data-medlem derefereres og verdien som returneres.

I tillegg bør denne metoden fungerer uavhengig av pakke spørsmål - kompilatoren er gratis å puten Vertex struktur, men det liker, og det vil fortsatt fungere helt fint. En anonym union vil støte på problemer hvis de flyter er pakket annerledes.

Svarte 30/01/2009 kl. 07:12
kilden bruker

stemmer
3

Referanser?

template<typename T>
struct vertex {
    vertex() :
        r(data[0]), g(data[1]), b(data[2]),
        x(data[0]), y(data[1]), z(data[2])
    {
    }

    T *operator *() {
        return data;
    }

    const T *operator *() const {
        return data;
    }

    T data[3];
    T &r, &g, &b;
    T &x, &y, &z;
};
Svarte 30/01/2009 kl. 13:05
kilden bruker

stemmer
3

Du kan få denne med en union som andre har nevnt. Overbelastning og -posisjonen på den samme struktur som dette kan ikke være en god idé (for eksempel ved å legge to farger vanligvis betyr at du ønsker å mette til 1,0, mens tilsetning av vektorer skjer lineært), men overlegging av en float [] på toppen av dem som det er helt greit og en godt akseptert middel for å bytte data med GL / DirectX / etc.

Jeg anbefaler at du unngår å henvise til samme medlem av forskjellige aliaser i samme funksjon omfang, men fordi dette vil drive deg inn i en ekkel maskinvare stall kalt en last-hit-butikken. Spesielt unngå dette hvis du kan:

vector foo; 
foo.x = 1.0f;
return foo[0] + foo[1];
Svarte 30/01/2009 kl. 06:05
kilden bruker

stemmer
2

Følgende struktur vil ha bedt om atferd:

struct vertex
{
private:
    float data[3];
public:
    float &x, &y, &z;
    float &r, &g, &b;

    vertex() : x(data[0]), y(data[1]), z(data[2]), r(data[0]), g(data[1]), b(data[2]) {
    }

    float& operator [](int i) { 
        return data[i];
    }
};
Svarte 24/03/2015 kl. 16:38
kilden bruker

stemmer
2

Jeg er ikke sikker på om jeg forstod spørsmålet riktig. Men det ser ut som du trenger for å overbelaste operatøren [] for å gi matrise som tilgang til struct / klasse. Se eksempel nevnes her: Operatør overbelastning

Svarte 30/01/2009 kl. 06:11
kilden bruker

stemmer
1

Dårlig idé etter min mening, i hvert fall for eksempel gitt: ulempen er at for bare om noen løsning på dette, er du sannsynligvis kommer til å være i stand til å fritt tildele "RGB" instanser til / fra "xyz" forekomster som er trolig sjelden fornuftig eller korrekt. dvs. at du risikerer å gi opp noen nyttig type sikkerhet.

Personlig, for eksempel du gir, vil jeg underklasse RGB og xyz typer fra en base boost::array<float,3>eller lignende. Så begge arve operatør [], kan sendes til funksjoner forventer matriser, og passerte med flere typer sikkerhet til ting som forventer farger / koordinater. Det er ofte du ønsker å behandle en xyz eller en rgb som en matrise, men sjelden du ønsker å behandle en xyz som en rgb eller vice-versa. (RGB-A matrisen. OK xyz ER-A matrisen. OK RGB-A xyz ???? Jeg tror ikke det!)

Selvfølgelig betyr adgang til x, y, z & r, g, b må være av tilgangsanordning (videresending til den riktige operator[](...)) snarere enn direkte til medlemmet. (Du trenger C # eiendommer for det).

Svarte 30/01/2009 kl. 13:49
kilden bruker

stemmer
1

Jeg antar at du kan gjøre noen makro magi for å få det du ønsker. Men det vil se stygge. Hvorfor ønsker du å bruke samme struct, toppunkt for 3 forskjellige typer? Hvorfor kan du ikke definere klassen for farge? Også huske på at toppunktet og farge er ikke samme. Hvis du endrer noe til toppunktet, vil det påvirke fargen også, hvis du har samme klasse for begge.

Svarte 30/01/2009 kl. 05:59
kilden bruker

stemmer
0

Bare en advarsel om bruk av referanse medlemmer peker til verdi medlemmer. Du må definere en kopi konstruktør (og muligens også oppdrag operatør), hvis du noen gang kopiere et slikt objekt (som overfører den etter verdi). Standard kopi konstruktør vil forlate deg med en kopi som referanse medlemmer peker på verdien medlemmer av det opprinnelige objektet, ikke de av det nye objektet. Dette er absolutt ikke noe du ønsker.

Vurderer du også ende opp med større gjenstander, som allerede påpekt, tror jeg å bruke tilgangsmetoder er å foretrekke fremfor referanse medlemmer.

Svarte 08/03/2009 kl. 16:54
kilden bruker

stemmer
0

Du kan prøve å legge referanser til variabler, som dette:

struct test {
        float x, y, z;
        float &r, &g, &b;

        test() : r(x), g(y), b(z) {}
    };

Men strukturen blir større (fra 12 bytes 40 bytes).

For å bruke [] på den, bruker overbelastning av operatoren [], som nevnt før.

Svarte 30/01/2009 kl. 13:07
kilden bruker

stemmer
0

Jeg har en mal og to Vector klasser under, en gal, en tilregnelig. Malen implementerer en enkel fast ved kompilering matrise av verdier. Den er designet for subclassing og bruker et beskyttet rekke variabel for å unngå at du må hoppe gjennom ringer for å få tilgang til array. (Noen folk liker kanskje ikke et slikt design. Jeg sier, hvis underklasser ringer dine belastet operatører, kan koblingen være en god idé.)

Den gale klassen lar deg ha medlemsvariable som heter x, y, z, og det fungerer som en matrise for samtaler til glGetFloatV. Den normal man har bare aksessoregenskaper funksjoner x (), y (), z () og fremdeles arbeider med glGetFloatV. Du kan bruke enten klassen som grunnlag for andre vektorobjekter du kan passere til OpenGL biblioteket. Selv klassene nedenfor er spesifikke for poeng, kan du selvsagt bare gjøre et søk / erstatt å slå dem inn i en rgb farge klasser.

Den gale klassen er gal fordi kostnaden av syntetisk sukker vec.x stedet for vec.x () er 3 referanse variabler. Det kan ta opp mye plass i et stort program. Bruk enklere tilregnelig versjon.

template <typename T, int N>
class FixedVector {
protected:
    T arr[N];
public:
    FixedVector();

    FixedVector(const T* a) {
        for (int i = 0; i < N; ++i) {
            arr[i] = a[i];
        }
    }

    FixedVector(const T& other) {
        for (int i = 0; i < N; ++i) {
            arr[i] = other.arr[i];
        }
    }

    FixedVector& operator=(const T& other) {
        for (int i = 0; i < N; ++i) {
            arr[i] = other.arr[i];
        }
        return *this;
    }

    T* operator&() { return arr; }
    const T* operator&() const { return arr; }

    T& operator[](int ofs) { 
        assert(ofs >= 0 && ofs < N);
        return arr[ofs];
    }
    const T& operator[](int ofs) const { 
        assert(ofs >= 0 && ofs < N);
        return arr[ofs];
    }
};

class CrazyPoint :  public FixedVector<float, 3> {
public:
    float &x, &y, &z;

    CrazyPoint()
      : x(arr[0]), y(arr[1]), z(arr[2])
    { arr[0] = arr[1] = arr[2] = 0.0; }

    CrazyPoint(const float* a)
      : x(arr[0]), y(arr[1]), z(arr[2])
    {
        arr[0] = a[0];
        arr[1] = a[1];
        arr[2] = a[2];
    }

    CrazyPoint(float a, float b, float c) 
      : x(a), y(b), z(c)
    {
        arr[0] = a;
        arr[1] = b;
        arr[2] = c;
    }
};

class SanePoint : public FixedVector<float, 3> {
public:
    float& x() { return arr[0]; }
    float& y() { return arr[1]; }
    float& z() { return arr[2]; }

    SanePoint() { arr[0] = arr[1] = arr[2] = 0.0; }
    SanePoint(float a, float b, float c) 
    {
        arr[0] = a;
        arr[1] = b;
        arr[2] = c;
    }
};

// usage
SanePoint normal;
glGetFloatV(GL_CURRENT_NORMAL, &normal);
Svarte 30/01/2009 kl. 10:20
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more