Forum: Compiler & IDEs typeof-operator und non-static data members


von A. N. (netbandit)


Lesenswert?

Hallo,

ich frage mich die ganze Zeit schon, warum der typeof-operator (und der 
zukünftige decltype-operator) nicht mit non-static data members einer 
Klasse zusammen arbeitet.

Beispiel:
1
class A {
2
  int B;
3
  typeof(B); // Error, wegen Zugriff auf nicht 
4
             // statisches Klassenattribut
5
}

Dabei spielt es doch gar keine Rolle ob B statisch oder nicht statisch 
ist... B hat einen Datentypen und den will ich mit typeof in diesem 
(zugegebenermaßen hier etwas sinnlosen) Zusammenhang ermitteln.

Kann mir jemand erklären warum dies nicht funktioniert? Mir fällt 
einfach keine sinnvolle Begründung dafür ein, aber vielleicht weiß ja 
ein GCC Spezialist mehr darüber...?

Ich danke schon einmal im Voraus,
Netbandit

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ich kenne typeof nur von C, da liefert es den Typ eines Objekts. So wie 
es bei dir steht, müsste es doch bereits einen Syntax-Fehler geben.
1
int B;
2
typeof(B) C; // C ist vom gleichen Typ wie B

Für C++ muss vielleicht mit -frtti übersetzt werden, wenn der Typ zur 
Compilezeit nicht bekannt ist.

Johann

von A. N. (netbandit)


Lesenswert?

Hallo,

typeof wird ja zur Compilierzeit ausgewertet. Für die Laufzeitauswertung 
gibt es ja glaube ich typeid oder so.

Im Grunde dürfte typeof für C++ und C gleich arbeiten. Beispiel:
1
void main(void) {
2
  int A;
3
  typeof(A) B;
4
5
  while(1) {
6
  }
7
  return;
8
}

In diesem Beispiel ist B vom Typ int. Genauso klappt das auch bei C++ 
mit Objekten und Klassenattributen bzw. mit statischen 
Klassenattributen:
1
class CA {
2
  int i;
3
}
4
5
void main(void) {
6
  CA A;
7
  typeof(A.i) B;
8
9
  while(1) {
10
  }
11
  return;
12
}

Hier ist B dann auch vom Typ integer. Leider brauche ich halt immer ein 
Objekt von der Klasse um typeof anwenden zu können oder aber i muss ein 
statischen Klassenattribut sein. Ich verstehe doch nicht warum. Typeof 
wird zur Compilierzeit ausgewertet und um den Typ zu ermitteln ist es 
doch völlig unerheblich ob die Variable im Form eines Objektes oder im 
Form eines statischen Attributes schon Speicher belegt oder nicht, ich 
will ja nur ihren Datentypen wissen.

von yalu (Gast)


Lesenswert?

In C++ scheint keine Syntax vorgesehen zu sein, mit der ohne die
Benutzung einer Instanz direkt auf ein nichtstatisches Element einer
Klasse zuzugriffen werden kann.

Normalerweise ist es ja auch wenig sinnvoll auf etwas zuzugreifen, was
gar nicht existiert. Einen Sonderfall stellen die Operatoren typeof
und sizeof dar, da diese nicht das Element selbst, sondern nur dessen
Eigenschaften (Typ bzw. Größe) kennen müssen. Aber nur für diese beiden
Operatoren wollten die C++-Entwickler wohl kein eigenes Sprachkonstrukt
definieren.

Wenn innerhalb der Klassendeklaration von A (aber außerhalb der
Definition von Elementfunktionen) der nichtglobale Indentifier B
auftaucht, ist B nichts anderes als die Abkürzung für A::B, und A::B ist
nun einmal die Syntax für den Zugriff auf ein statisches Datenelement
der Klasse.

Immerhin gibt einen Hack, mit dem man das Problem zumindest teilweise
umgehen kann: Man definiert eine Pseudoinstanz von A an der Adresse 0
(oder sonstwo). Da auf die Instanz nicht wirklich zugegriffen wird, ist
das in Ordnung, wenn auch unschön:
1
  typeof ((A *)0)->B

bzw.
1
  sizeof ((A *)0)->B

Der Hack funktioniert aber nur außerhalb der Klassendeklaration von A.
Versucht man, ihn innerhalb der Klassendeklaration anzuwenden, meckert
der GCC schon wieder:
1
  error: invalid use of incomplete type ‘class A’

was ebenfalls schwer nachzuvollziehen ist, da er zur Bestimmung der
Eigenschaften von B ja nicht die gesamte Klasse kennen muss.
Wahrscheinlich hängt das damit zusammen, dass der Compiler erst dann mit
Instanzen umgehen kann, wenn die zugehörige Klasse als Ganzes bekannt
ist.

Das sind bei weitem nicht die einzigen Fälle, wo die Sprachdefinition
von C++ etwas krumm ist. Java und C# sind in dieser Hinsicht sicher
sauberer definiert (man hat ja hoffentlich dazugelernt).Trotzdem ist C++
in meinen Augen nach wie vor die beste Vereinigung der C-Philosophie
(Hardwarenähe, Determinismus usw.) und der objektorientierten
Programmierung.

von A. N. (netbandit)


Lesenswert?

Hallo yalu,

danke für dein Post. Ich habe sogar noch ein anderes Workaround 
gefunden, welches  auch innerhalb der Klasse funktioniert.
1
template<typename T>
2
struct get_type {};
3
4
template<typename R, typename T>
5
struct get_type<R T::*>
6
{
7
  typedef R type;
8
};
9
10
#define GETTYPE(ELEMENT) get_type<typeof(&ELEMENT)>::type

Nun kann ich das machen:
1
class A {
2
  int B;
3
  GETTYPE(A::B) C;
4
}

Diese, meiner Meinung nach, geniale Lösung kommt von Mathias Gaunard aus 
der Mailingliste vom GNU C++ und läuft bei mir inzwischen auch ganz gut.
Es gibt halt manchmal schon Fälle wo man den Datentyp auf dieser Art und 
Weise bestimmen möchte, da es nicht mehr so leicht nachvollziehbar ist 
welcher Datentyp zu einem Klassenmember gehört oder nicht.

Du vermutest ja, dass es sich bei der Einschränkung des typeof bzw. 
sizeof Operators auf nicht statische oder als Objekt vorhandene 
Elemente, eher um zufälliges Versäumnis beim GCC handelt. Immerhin ist 
ja der typeof-Operator eine Eigenheit des GCCs selbst, ok da kann ich 
mir das schon vorstellen, das man damals einfach nicht daran gedacht 
hat, dass man den in diesem Kontext verwenden möchte. Was ich aber nicht 
nachvollziehen kann ist, dass die gleiche Einschränkung offensichtlich 
auch beim im C++09-Standard geplanten Operator decltype gelten soll. 
Immerhin hat man sich hier hingesetzt und sich Gedanken dazu gemacht, 
wie dieser zu verwenden sei. Daher gehe ich davon aus, dass es einen 
guten Grund gibt, ihn nicht so zu verwenden, ansonsten würde doch 
absolut nichts dagegen sprechen ihn entsprechend zu definieren (wenn man 
eh schon dabei ist).

von yalu (Gast)


Lesenswert?

> Diese, meiner Meinung nach, geniale Lösung kommt von Mathias Gaunard
> aus der Mailingliste vom GNU C++ und läuft bei mir inzwischen auch
> ganz gut.

Manomann, diese Lösung hat's wirklich in sich! Auf die Idee mit den
Elementzeigern bin ich auch noch gekommen, aber diese alleine bringen ja
nicht viel, weil man für deren Dereferenzierung wieder eine Instanz
braucht. Die Elementzeiger aber mit einer über zwei unterschiedliche
Templates deklarierten Hilfsstruktur zu kombinieren, darauf muss man
erst einmal kommen :)

> Daher gehe ich davon aus, dass es einen guten Grund gibt, ihn nicht so
> zu verwenden, ansonsten würde doch absolut nichts dagegen sprechen ihn
> entsprechend zu definieren (wenn man eh schon dabei ist).

Vielleicht ist der Grund ja der, dass das Problem ja ganz einfach
mittels Templates umgangen werden kann ;-)

von A. N. (netbandit)


Lesenswert?

yalu wrote:
> Vielleicht ist der Grund ja der, dass das Problem ja ganz einfach
> mittels Templates umgangen werden kann ;-)

Ach so, du meinst also nach dem Motto: "Warum einfach wenn es auch 
kompliziert klappt..."

Hehe, daran hab ich noch gar nicht gedacht ;)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.