2010-08-09 13 views
9

Próbka o zredukowanym kodzie próbnym nie robi nic użytecznego, ale dwa kolejne przypisania do wskaźnika elementu danych. Pierwsze przypisanie działa, drugie daje błąd kompilatora. Prawdopodobnie dlatego, że jest to element zagnieżdżony.Zagnieżdżony wskaźnik elementu danych - niemożliwe?

Pytanie brzmiało: czy nie jest możliwe, aby wskaźnik elementu wskazywał na element zagnieżdżony lub czy brakuje mi tam jakiejś wymyślnej składni?

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 Pracuję nad wykorzystaniem przesunięć bajtów i wielu rzutów. Ale to jest brzydkie, chciałbym raczej użyć tych wskaźników dla członków.

Tak, wiem, że to pytanie z pewnością powstało wcześniej (jak prawie każde pytanie). Tak, wcześniej szukałem, ale nie znalazłem satysfakcjonującej odpowiedzi.

Dzięki za poświęcony czas.

+0

jpalecek jest poprawny; odpowiedź na twoje pytanie brzmi: nie. Ale to, czego naprawdę szukasz, to rozwiązanie problemu. Po drobnej restrukturyzacji danych możesz znaleźć typ, który wskazuje na wszystkie cztery pływaki. (Patrz poniżej.) –

Odpowiedz

4

AFAIK, to nie jest możliwe. Wskaźnik do członka może być utworzony jedynie przez wyrażenie typu &qualified_id, co nie jest twoim przypadkiem.

Rozwiązanie Vite Falcon jest prawdopodobnie najbardziej odpowiednie.

+0

Obawiam się, że to po prostu niemożliwe. Być może muszę trzymać się swojego rozwiązania offsetowego. Korzystanie z bezwzględnych wskaźników float nie będzie takie samo. –

+0

Chociaż nie podoba mi się odniesienie do Falcona, twoja Odpowiedź jest prawdopodobnie właściwa. To niemożliwe - niestety. –

5

Zakładam, że próbujesz uzyskać wskaźnik do datamember Red. Ponieważ jest to zdefiniowane w strukturze Color, typ wskaźnika to Color::*. Stąd Twój kod powinien być:

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

Aby z niego skorzystać, musisz powiązać go z instancją Color na przykład:

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

EDIT: Czy nie jest możliwe, aby funkcję animacji szablon? Na przykład:

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; 
} 
+0

Ma to duży problem, że nie można animować jasności w tej architekturze. – jpalecek

+0

@jpalecek: Tak, masz rację. Koncentrowałem się bardziej na składni. – Naveen

+0

Uhm, tak, ale użycie różnych wskaźników uczyniłoby całą rzecz bezcelową. Chcę, aby pojedynczy wskaźnik, który przechowuje, pływający w materiale (lub jego zagnieżdżonych elementach), musi być animowany. W rzeczywistości mam oczywiście jeszcze więcej członków zagnieżdżonych w materiale. Teoretycznie powinno być możliwe. Moje rozwiązanie z przesunięciami bajtów i wieloma rzutami działa. To tylko kwestia składni. –

2

Zasadniczo próbujesz uzyskać wskaźnik do zmiennej zmiennoprzecinkowej, którą możesz animować. Dlaczego nie użyć float*. Problem, który tam masz, polega na tym, że Brightness jest członkiem materiału, jednak Red jest członkiem Color, a nie Material, kompilatorem. Użycie numeru float* powinno rozwiązać Twój problem.

+0

Prosty wskaźnik pływający byłby bezwzględnym wskaźnikiem do pojedynczej lokalizacji pamięci. Nie można go użyć na kilku obiektach materialnych i straciłby ważność, gdyby materiał zmienił położenie pamięci. –

+1

O ile rozumiem, wskaźnik zawsze będzie nieprawidłowy, jeśli materiał zmieni jego położenie w pamięci. Żaden wskaźnik nie zmienia położenia pamięci. –

+2

Wskaźniki członków śledzą lokalizacje w pamięci! Są to tylko względne przesunięcia w obiekcie. Musisz określić dodatkową instancję, aby uzyskać do nich dostęp. –

2

Zamiast wskaźnika elementu można użyć funktora, który zwraca wartość float*, gdy podano instancję Material; zmienić typ ParamToAnimate do czegoś podobnego:

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

na plus, to przenośny - ale na domiar złego, to wymaga znacznych ilości kodu boilerplate i ma znaczny narzut wykonania.

Jeśli jest to krytyczne z punktu widzenia wydajności, byłbym skłonny trzymać się metody offsetowej.

+0

Masz pomysł, ale tak, to jest krytyczne. Pracuję nad mechanizmem 3D w czasie rzeczywistym. –

+1

Wtedy przesunięcie hack/metoda jest prawdopodobnie lepsza. –

0

Po prostu można refaktoryzować, tak aby w ogóle nie mieć struktury zagnieżdżonej. Dodaj setera, niż rozpakowuje kolor na jego części składowe, tak aby istniejący kod nie musiał się zbytnio zmieniać i przejść dalej.

Można również wziąć opcjonalny drugi wskaźnik, który wykopuje typ zagnieżdżony.Pojedynczy test, aby sprawdzić, czy potrzebujesz drugiego parametru, może okazać się wystarczająco dobry w porównaniu do aktualnej metody i byłby łatwiejszy do przedłużenia, gdyby dodatkowe pola pojawiły się później.

Zrób krok dalej i masz podstawową klasę MaterialPointer z wirtualną metodą Dereference. Klasa case może obsługiwać proste elementy członkowskie, a klasy pochodne obsługują zagnieżdżone elementy wraz z dodatkowymi informacjami potrzebnymi do ich znalezienia. Fabryka może następnie produkować obiekty odpowiedniego typu. Oczywiście, teraz utknąłeś z przydziałami sterty, więc jest to prawdopodobnie zbyt daleko, aby być praktycznym.

+0

Wszystkie te są możliwe alternatywy. Ale są też bardziej skomplikowane i/lub mniej wydajne niż moje istniejące rozwiązanie z przesunięciami bajtów i rzutami. –

0

Ponieważ w pewnym momencie trzeba wskaźnik do rzeczywistych danych, to może lub nie może pracować dla Ciebie:

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; 
+0

Tak, to kolejny wskaźnik o innym typie. Nie pomogłoby uczynić tego wszystkiego prostszym i bardziej eleganckim. –

0

Jak o dziedziczeniu zamiast składzie?

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; } 
Powiązane problemy