2 Stimmen

Probleme bei der Suche nach C++-Klassenmitgliedernamen (in Bezug auf den Wortlaut der Norm n3225)

Ich bin sehr verwirrt über die Norm 10.2/13,

[Hinweis: Auch wenn das Ergebnis der Namenssuche eindeutig ist, kann die Verwendung eines Namens, der in mehreren Unterobjekten gefunden wird, mehrdeutig sein (4.11, 5.2.5, 5.3.1, 11.2). end note ] [ Beispiel:

struct B1 {
  void f();
  static void f(int);
  int i;
};
struct B2 {
  void f(double);
};
struct I1: B1 { };
struct I2: B1 { };
struct D: I1, I2, B2 {
  using B1::f;
  using B2::f;
  void g() {
    f(); // Ambiguous conversion of this
    f(0); // Unambiguous (static)
    f(0.0); // Unambiguous (only one B2)
    int B1::* mpB1 = &D::i; // Unambiguous
    int D::* mpD = &D::i; // Ambiguous conversion
  }
};

Ich kann nicht erkennen, warum dies eindeutig ist int B1::* mpB1 = &D::i; // Eindeutig

Visual C++, Gcc und CLang sagen alle, dass der Zugriff auf D::i zweideutig ist!

Die Formulierung scheint mit dem Kernproblem #39 zusammenzuhängen http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#39 und der endgültige Vorschlag ist hier zu finden: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1626.pdf

Ich finde nun, dass die neuen, auf dem Algorithmus basierenden Formulierungen (10.2/3-10.2/6) noch verwirrender sind, weil keine der Noten in 10.2/9, 10.2/10, 10.2/11 und 10.2/13 vollständig mit 10.2/3-10.2/6 übereinstimmt. Ich kann 10.2/9-10.2/11 als Ausnahmen betrachten, aber 10.2/13 verwirrt mich besonders. Ich habe keine Ahnung, was mit 10.2/13 bezweckt wird.

Wie ist das Beispiel in 10.2/13 nach den 10.2/3-10.2/6 zu sehen? Was ist die Intention von 10.2/13, d.h., wie ist die Situation, dass 10.2/13 als Ausnahme von 10.2/3-10.2/6 betrachtet wird?

Bitte geben Sie mir einige Hinweise. Ich danke Ihnen vielmals.


Nach einigem Nachdenken scheint mir die Absicht von 10.2/13 klarer zu sein.

int B1::* mpB1 = &D::i; // Eindeutig

Dies sollte eindeutig sein, und die derzeitigen Compiler sind in diesem Punkt falsch. Dies ist eindeutig, weil die Initialisierung von Zeigern auf Klassenmitglieder noch nicht den Zugriff auf das Objekt beinhaltet.

int D::* mpD = &D::i; // Zweideutige Umwandlung

Dies bedeutet, dass bei der Konvertierung von int B1::*mpB1 nach int D::*mpD die Konvertierung aufgrund von mehrdeutigen Basisklassen mehrdeutig ist.

4voto

Keith Punkte 6658

Für den Fall B1::* ist die Interpretation eindeutig, es handelt sich einfach um den Offset vom Beginn von B1 bis i.

In 5.3.1/3:

struct A { int i; };
struct B : A { };
... &B::i ... // has type int A::*

Der Trick besteht also darin, dass &D::i von vornherein vom Typ B1::* sein muss. Dann:

int B1::* mpB1 = &D::i; // Unambiguous

ist einfach. Dann kommen die Zinsen ins Spiel:

int D::* mpD = &D::i; // Ambiguous conversion

Hier ist das RHS vom Typ B1::* und muss umgewandelt werden, da wir feststellen müssen, auf welche Basis sich der Wert bezieht.

2voto

Martin York Punkte 245363

Dies:

int B1::* mpB1 = &D::i; // Unambiguous

ist eindeutig, da das Ergebnis einem pointer to member der Klasse B.
Es spielt also keine Rolle, welche i gewählt, da sich der Versatz auf ein B-Mitglied bezieht (nicht auf die übergeordnete D-Klasse).

Für Sie und mich ist es also eindeutig, aber ich glaube nicht, dass der Compiler damit umgehen kann.

0voto

J-16 SDiZ Punkte 25675

Eine kurze Überprüfung der ISO IEC 14882 2003 Abschnitt 10 enthält weder dieses noch ein ähnliches Beispiel. C++0x ist Entwurf Standard, und VC++/GCC/CLang sind nicht konform mit ihm.

Meine Vermutung: Dies ist ein Nebenprodukt der neuen auto Typisierung und nicht im älteren C++-Standard zu finden.

0voto

FWIW, ich kopiere meine Antwort, die ich auf die Usenet-Kopie dieser Frage gegeben habe:

Hallo zusammen,
 
Ich bin sehr verwirrt über die Norm n3225 10.2/13,  
[Hinweis: Selbst wenn das Ergebnis der Namenssuche eindeutig ist, kann die Verwendung eines Namen, der in mehreren Unterobjekten gefunden wird, immer noch mehrdeutig sein (4.11, 5.2.5, 5.3.1, 11.2).-end note ] [ Beispiel:  

struct B1 {
  void f();
  static void f(int);
  int i;
};
struct B2 {
  void f(double);
};
struct I1: B1 { };
struct I2: B1 { };
struct D: I1, I2, B2 {
  using B1::f;
  using B2::f;
  void g() {
    f(); // Ambiguous conversion of this
    f(0); // Unambiguous (static)
    f(0.0); // Unambiguous (only one B2)
    int B1::* mpB1 = &D::i; // Unambiguous
    int D::* mpD = &D::i; // Ambiguous conversion
  }
};

Ich kann nicht erkennen, warum dies eindeutig ist int B1::* mpB1 = &D::i; // Eindeutig  

&D::i hat Typ int B1::* und bezieht sich eindeutig auf das Datenelement i von  B1 . Wenn Sie es mit einer Dereferenzierung D Objekt oder wenn Sie es einem int  D::* erhalten Sie eine Zweideutigkeit nach Bedarf. 

Visual C++, Gcc und CLang sagen alle, dass der Zugriff auf D::i zweideutig ist!  

Keiner dieser Compiler implementiert 10.2 bisher. 

Die Formulierung scheint mit dem Kernproblem #39 zusammenzuhängen http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#39 und den endgültigen Vorschlag finden Sie hier: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1626.pdf   Ich finde nun, dass die neuen, auf dem Algorithmus basierenden Formulierungen (10.2/3-10.2/6) noch verwirrender sind, weil keine der Anmerkungen in 10.2/9, 10.2/10, 10.2/11 und 10.2/13 nicht vollständig mit 10.2/3-10.2/6 übereinstimmt. Ich kann die 10.2/9-10.2/11 als Ausnahmen ansehen, aber ich bin besonders verwirrt über 10.2/13. Ich habe keine Ahnung, was mit 10.2/13 bezweckt wird.  

Sie müssen Beispiele anführen, die zeigen, was Sie nicht verstehen. 

Wie ist das Beispiel in 10.2/13 nach den Regeln der 10.2/3-10.2/6? Was ist die Intention von 10.2/13, d.h., was ist die Situation, in der 10.2/13 als Ausnahme von 10.2/3-10.2/6 betrachtet wird? 10.2/3-10.2/6?  

Die neuen, auf Algorithmen basierenden Suchregeln entkoppeln Laufzeitbelange (Auffinden eines  eindeutiges Objekt) von den Belangen der Kompilierzeit/des Nachschlagens (Auffinden einer Deklaration, die  auf die sich ein Name bezieht). 

Der folgende Text ist mit der neuen Formulierung wohlgeformt:

struct Z { int z; };
struct X : Z { };
struct Y : Z { };
struct A : X, Y { };

struct B : A {
  using A::z;
};

Die Erklärung using A::x; führt einen Mitgliedsnamen in B ein, der sich auf  die Erklärung Z::z . In einem deklarativen Kontext ist dies völlig in Ordnung. Ein  Fehler tritt nur auf, wenn Sie auf B::z als Mitglied Zugriff Ausdruck  (5.2.5). 

Fühlen Sie sich nicht schlecht, wenn Sie sich in der Sache mit dem Mitgliederzeiger geirrt haben. Ich habe das auch getan in der Vergangenheit, und die entsprechenden Emissionsbericht hat es tatsächlich in einen C++0x-Entwurf geschafft. Sie haben glücklicherweise zurück geändert als sie bemerkten, dass die Veränderung falsch war.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X