Verschachtelte Datenelementzeiger - nicht möglich?
-
27-09-2019 - |
Frage
Der gehorchen, zurückzuweisen reduziert Codebeispiel tut nichts nützlich, sondern zwei nachfolgende Zuweisungen zu einem Datenelementzeiger. Die ersten assignement funktioniert, gibt der zweite einen Compiler-Fehler. Vermutlich, weil sie zu einem verschachtelten Elemente.
Frage wäre: Ist es wirklich einfach nicht möglich, einen Elementzeiger Punkt zu einem verschachtelten Mitglied zu lassen oder bin ich dabei jeden Wunsch Syntax gibt
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 Ich arbeite mit Hilfe Byteversätze und viele Würfe um. Aber das ist hässlich, würde ich besser wie diejenigen Mitglieds Zeiger zu verwenden.
Ja, ich weiß, diese Frage sicherlich arised vor (wie fast jede Frage). Ja, ich gesucht vorher fand aber keine befriedigende Antwort.
Vielen Dank für Ihre Zeit.
Lösung
AFAIK ist dies nicht möglich. Ein Zeiger-to-Mitglied kann nur durch einen Ausdruck des Typs &qualified_id
gebildet werden, was nicht der Fall ist.
Vite Falcon-Lösung ist wahrscheinlich die am besten geeignet.
Andere Tipps
Ich nehme an, Sie versuchen, den Zeiger auf die Datamember Red
zu bekommen. Da dies in dem struct Color
definiert ist, ist die Art des Zeigers Color::*
. Daher sollten Sie den Code sein:
int main() {
float Color::* ParamToAnimate;
ParamToAnimate = &Color::Red;
return 0; }
Um es zu nutzen, müssen Sie es auf eine Instanz Color
zum Beispiel binden:
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;
}
Bearbeiten : Ist es nicht möglich, die Animationsfunktion einer Vorlage zu machen? Zum Beispiel:
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;
}
Statt eines Mitglieds Zeiger, können Sie einen Funktor, dass die Renditen ein float*
verwenden, wenn eine Instanz von Material
gegeben; ändert die Art der ParamToAnimate
zu so etwas wie:
std::function<float*(Material&)>
Auf der positiven Seite, es ist tragbar -. Aber auf der Kehrseite, es erfordert eine erhebliche Menge an Standardcode und hat signifikanten Laufzeitaufwand
Wenn diese Leistung entscheidend ist, würde ich mit der Offset-Methode Stick versucht werden.
Im Grunde versucht man, einen Zeiger auf eine Variable vom Typ float zu bekommen, dass Sie animieren können. Warum float*
nicht. Das Problem Sie haben es, dass Brightness
ist Mitglied Material, jedoch ist Red
Mitglied Color
und nicht Material
, an den Compiler. Mit float*
sollte Ihr Problem lösen.
Es ist nicht möglich. Aber es gibt eine Abhilfe ganz in der Nähe zu dem, was Sie erreichen wollen. Es geht um Putting das verschachtelte Mitglied in einer Vereinigung zusammen mit einem „Layout-kompatibel“ anonymous Struktur. Der Nachteil ist ein bisschen aufgebläht Schnittstelle und die Notwendigkeit von Definitionen von Geschwister structs synchron zu halten.
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
Wenn zwei Typen T1 und T2 vom gleichen Typ ist, dann T1 und T2 Layout-kompatible Typen. [Hinweis: Layout-kompatibel Aufzählungen sind in 7.2 beschrieben. Layout-kompatibel POD-Strukturen und POD-Gewerkschaften in 9.2 beschrieben. ]
§9.2
16
Wenn ein POD-Union enthält zwei oder mehr POD-Strukturen, die eine gemeinsame teilen Anfangssequenz, und wenn das POD-Union Objekt enthält derzeit eine dieser POD-structs, ist es erlaubt, den gemeinsamen Anfang zu inspizieren Teil eines von ihnen. Zwei POD-structs eine gemeinsame Anfangssequenz wenn entsprechende Elemente haben Layout-kompatible Typen (und für Bitfelder, die gleiche Breite) für eine Folge von einer oder mehreren Anfängen Mitglieder.
Mehrere Verschachtelung möglich ist, auch:
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
Zwei POD-Struktur (Ziffer 9) Typen sind Layout-kompatibel, wenn sie die haben dieselbe Anzahl von nicht-statischen Datenelemente und entsprechende nicht-statische Datenelemente (in der Reihenfolge) haben Layout-kompatible Typen (3.9).
Sie könnten einfach so umgestalten, dass Sie nicht über die verschachtelte Struktur überhaupt. Fügen Sie einen Setter als entpackt die Farbe in seine Bestandteile, so dass bestehende Code muss nicht viel ändern, und gehen von dort aus.
Sie können auch einen optionalen zweiten Zeiger nehmen, die in den verschachtelten Typ gräbt. Ein einzelner Test, um zu sehen, wenn Sie den zweiten Parameter müssen gut genug beweisen kann Ihre aktuelle Methode im Vergleich zu, und würde leicht erweitert sollten zusätzliche Felder später wieder auftauchen.
Nehmen Sie das noch einen Schritt weiter, und Sie haben eine Basis MaterialPointer
Klasse mit einem virtuellen Dereference
Methode. Die Fallklasse können einfache Mitglieder handhaben, mit abgeleiteten Klassen verschachtelte Elemente mit dem, was sie zusätzliche Informationen benötigen Umgang mit ihnen zu finden. Eine Fabrik kann dann MaterialMember*
produzieren Objekte des entsprechenden Typs. Natürlich, jetzt bist du mit Heapzuweisungen stecken, so ist dies wahrscheinlich ein wenig zu weit, praktisch zu sein.
Da an einem gewissen Punkt müssen Sie einen Zeiger auf die tatsächlichen Daten, dies kann oder auch nicht für Sie arbeiten:
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;
Wie wäre es Vererbung statt Zusammensetzung?
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; }