Domanda

L'esempio di codice foolowing ridotta non fa nulla di utile, ma due successive assegnazioni a un puntatore membro dati. Le prime opere assegnazione, il secondo dà un errore di compilazione. Presumibilmente perché il suo a un membro nidificato.

domanda sarebbe:? E 'davvero solo non è possibile lasciare che un punto puntatore membro a un membro nidificato o mi sto perdendo qualsiasi sintassi fantasia vi

struct Color {
    float Red;
    float Green;
    float Blue; };


struct Material {
    float Brightness;
    Color DiffuseColor; };


int main() {
    float Material::* ParamToAnimate;
    ParamToAnimate = &Material::Brightness;       // Ok
    ParamToAnimate = &Material::DiffuseColor.Red; // Error! *whimper*
    return 0; }

ATM sto lavorando intorno utilizzando scostamenti di byte e un sacco di calchi. Ma ciò che è brutto, sarei meglio come utilizzare tali puntatori membri.

Sì, so che domanda sicuramente arised prima (come quasi tutta la domanda). Sì, ho cercato in anticipo, ma ho trovato nessuna risposta soddisfacente.

Grazie per il vostro tempo.

È stato utile?

Soluzione

Per quanto ne so, questo non è possibile. Un membro puntatore a può essere costituito solo da un'espressione di tipo &qualified_id, che non è il caso.

La soluzione di Vite Falcon è probabilmente la più appropriata.

Altri suggerimenti

presumo si sta cercando di ottenere il puntatore alla Red DataMember. Poiché questo è definito nel Color struct il tipo del puntatore è Color::*. Quindi il codice dovrebbe essere:

int main() {
    float Color::* ParamToAnimate;
    ParamToAnimate = &Color::Red; 
    return 0; }

Per utilizzarlo, è necessario associarlo a un'istanza di Color ad esempio:

void f(Color* p, float Color::* pParam)
{
    p->*pParam = 10.0;
}
int main() {
    float Color::* ParamToAnimate;
    ParamToAnimate = &Color::Red; 

    Material m;
    f(&m.DiffuseColor, ParamToAnimate);
    return 0;
}

Modifica : Non è possibile effettuare la funzione di animazione un modello? Ad esempio:

template<class T>
void f(T* p, float T::* pParam)
{
    p->*pParam = 10.0;
}
int main() {

    Material m;

    f(&m.DiffuseColor, &Color::Red);
    f(&m, &Material::Brightness);
    return 0;
}

Al posto di un puntatore membro, è possibile utilizzare un funtore che restituisce un float* quando somministrato un'istanza di Material; cambiare il tipo di ParamToAnimate a qualcosa come:

std::function<float*(Material&)>

Sul lato positivo, è portatile -. Ma verso il basso, richiede una notevole quantità di codice standard e ha un overhead significativo runtime

Se questa è la prestazione critica, sarei tentato di attaccare con il metodo offset.

In sostanza si sta cercando di ottenere un puntatore ad una variabile float che si può animare. Perché non utilizzare float*. Il problema riscontrato è che Brightness è un membro del materiale, tuttavia, Red è membro di Color e non Material, al compilatore. Utilizzando float* dovrebbe risolvere il problema.

Non è possibile. Ma c'è una soluzione molto vicino a quello che si vuole raggiungere. Esso coinvolge mettere il membro nidificato in un'unione a fianco con una struttura anonima "Layout-compatibili". Il rovescio della medaglia è un'interfaccia gonfio po 'e la necessità di mantenere le definizioni di pari livello le strutture in sincronia.

struct Color {
    float Red;
    float Green;
    float Blue; };

struct Material {
    float Brightness;
    union {
        struct { // "Layout-compatible" with 'Color' (see citation below)
            float DiffuseColorRed;
            float DiffuseColorGreen;
            float DiffuseColorBlue; };
        Color DiffuseColor; }; };

int main() {
    Material M;

    float Material::* ParamToAnimate;
    ParamToAnimate = &Material::DiffuseColorRed;
    std::cin >> M.*ParamToAnimate;
    std::cout << M.DiffuseColor.Red << std::endl;
    return 0; }

ISO IEC 14882-2003 (c ++ 03):

  

§3.9

     

11

     

Se due tipi T1 e T2 sono dello stesso tipo, quindi T1 e T2 sono   tipi compatibili con il layout. [Nota: enumerazioni compatibili con layout sono   descritto in 7.2. Layout-compatibile POD-strutture e POD-sindacati sono   descritto al punto 9.2. ]

     

§9.2

     

16

     

Se un POD-union contiene due o più POD-le strutture che condividono una comune   sequenza iniziale, e se l'oggetto POD-unione attualmente contiene uno   di questi POD-struct, è consentito di ispezionare l'iniziale comune   parte di uno di essi. Due POD-struct condividono una sequenza iniziale comune   se i membri corrispondenti sono tipi compatibili layout (e, per   bit-campi, le stesse larghezze) per una sequenza di uno o più iniziale   membri.

nidificazione multiplo è possibile anche:

struct Color {
    float Red;
    float Green;
    float Blue; };

struct Material {
    float Brightness;
    Color DiffuseColor; };

struct Wall {
    union {
        struct {
            float SurfaceBrightness;
            struct {
                float SurfaceDiffuseColorRed;
                float SurfaceDiffuseColorGreen;
                float SurfaceDiffuseColorBlue; }; };
        Material Surface; }; };

int main() {
    Wall W;

    float Wall::* ParamToAnimate;
    ParamToAnimate = &Wall::SurfaceDiffuseColorRed;
    std::cin >> W.*ParamToAnimate;
    std::cout << W.Surface.DiffuseColor.Red << std::endl;
    return 0; }
  

§9.2

     

14

     

Due POD-struct (clausola 9) tipi sono compatibili con il layout se hanno il   stesso numero di membri dati non statici e non statica corrispondente   membri di dati (in ordine) sono tipi di formato compatibile (3.9).

Si potrebbe semplicemente refactoring in modo tale che non si ha la struttura annidata a tutti. Aggiungere un setter di Spacchetta il colore nelle sue componenti in modo che bisogno il codice esistente non cambia molto, e passare da lì.

Si potrebbe anche prendere un secondo puntatore opzionale che scava nel tipo nidificato. Un singolo test per vedere se è necessario il secondo parametro può rivelarsi abbastanza buono rispetto al vostro attuale metodo, e sarebbe più facilmente esteso dovrebbero campi aggiuntivi alzare tardi.

Prendi questo un ulteriore passo avanti, e si dispone di una classe base MaterialPointer con un metodo Dereference virtuale. La classe caso in grado di gestire i membri semplici, con le classi derivate di movimentazione membri nidificati con tutte le informazioni aggiuntive di cui hanno bisogno per trovarli. Una fabbrica possono poi produrre MaterialMember* oggetti del tipo appropriato. Naturalmente, ora sei bloccato con le allocazioni di heap, quindi questo è probabilmente un po 'troppo per essere pratico.

Dato che ad un certo punto è necessario un puntatore ai dati effettivi, questo può o non può funzionare per voi:

float Material::* ParamToAnimate;
ParamToAnimate = &Material::Brightness;       // Ok
float Color::* Param2;
Param2 = &Color::Red; 

Material mat;
mat.Brightness = 1.23f;
mat.DiffuseColor.Blue = 1.0f;
mat.DiffuseColor.Green = 2.0f;
mat.DiffuseColor.Red = 3.0f;

float f = mat.DiffuseColor.*Param2;

Come su eredità, invece di composizione?

struct Color {
    float Red;
    float Green;
    float Blue; };

struct DiffuseColor : public Color {
    };

struct Material : public DiffuseColor {
    float Brightness; };


int main() {
    float Material::* ParamToAnimate;
    ParamToAnimate = &Material::Brightness;       // Ok
    ParamToAnimate = &Material::DiffuseColor::Red; // Ok! *whew*
    return 0; }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top