Template von teilbekanntem Template
-
Wie sieht den der Code aus der die Klasse benutzt?
-
Es gibt bisher keinen Code, der die beiden Templates verwendet. Ich werde aber mal einen schreiben, eine gute Idee, vielleicht sehe ich dann klarer. Der Fehler wird aber wohl bestehen bleiben ...
-
Wenn ich sowas hier mache:
template<class CLASS, template<typename CLASS> class CLASS_EXT> class CBeta { public: CBeta() { } }; template<class CLASS> class CAlpha { public: // Hier folgt eine fehlerhafte Zeile CAlpha(CBeta<CLASS, CAlpha> *pPointer) { } }; int main() { }funktioniert es bei mir ... (GCC) 4.6.2
Allerding bekomme ich eine Warnung:warning: injected-class-name `CAlpha<CLASS>::CAlpha' used as template template argumentEDIT: Probier mal in der fehlerhaften Zeile CAlpha durch ::CAlpha zu ersetzen. (also
CAlpha(CBeta<CLASS, ::CAlpha> *pPointer) { }) Bei mir ist die Warnung dann weg.
-
pyhax schrieb:
Allerding bekomme ich eine Warnung:
warning: injected-class-name `CAlpha<CLASS>::CAlpha' used as template template argumentEDIT: Probier mal in der fehlerhaften Zeile CAlpha durch ::CAlpha zu ersetzen. (also
CAlpha(CBeta<CLASS, ::CAlpha> *pPointer) { }) Bei mir ist die Warnung dann weg.Das setzt dann aber voraus, dass CAlpha im globalen Namensraum zu finden ist, also keine optimale Lösung. Die bloße Verwendung von CAlpha hier ist kein Fehler (14.6.1/1), der Nutzen der Warnung erschließt sich mir nicht.
-
Zusammenfassend,
folgdender Code läßt sich mit cl9.0 übersetzen und ausführen:
template<class CLASS, template<class CLASS> class CLASS_EXT> class CGamma { public: CGamma() { p1 = NULL; p2 = NULL; } protected: CLASS *p1; CLASS_EXT<CLASS> *p2; }; template<class CLASS> class CBeta { public: CBeta() { p = NULL; } CBeta(CGamma<CLASS, ::CBeta> *p) { this->p = p; } ~CBeta() { if(p) delete p; } const CGamma<CLASS, ::CBeta> *Get() const { return p; } protected: CGamma<CLASS, ::CBeta> *p; // gcc wohl auch: CGamma<CLASS, CBeta> *p }; class CAlpha { public: CAlpha(); }; int main(int argc, char* argv[]) { CBeta<CAlpha> beta(new CGamma<CAlpha, CBeta>()); const CGamma<CAlpha, CBeta> *p = beta.Get(); return 0; }Mein (Haupt-) Fehler (neben
(CGamma<CLASS, ::CBeta<CLASS> >statt(CGamma<CLASS, ::CBeta>) bestand darin, statt::CBetaeinfach nurCBetageschrieben zu haben. Der cl9.0 beschwert sich mit folgendem Fehler:Ungültiges Vorlagenargument für den Vorlagenparameter 'CLASS_EXT'; Klassenvorlage erwartet
Der gcc scheint laut Auskunft eines Kollegen hier nur eine Warnung auszugeben. Und genau das habe ich noch nicht ganz verstanden: Warum ist
::vor::CBetanötig? Welcher "andere" globale Namensraum (Mehrdeutigkeit?) ist denn hier gemein, da man doch ohne::bereits den globalen Namensraum anspricht?An alle die mir bis hierher weitergeholfen haben ein 42-faches Dankeschön!
-
Weispfenning schrieb:
Warum ist
::vor::CBetanötig? Welcher "andere" globale Namensraum (Mehrdeutigkeit?) ist denn hier gemein, da man doch ohne::bereits den globalen Namensraum anspricht?Der Clou ist, dass Innerhalb einer Klasse der Name der Klasse selbst nochmal injiziert wird. Im Scope einer Klasse A im globalen namespace ist also nicht nur das Symbol ::A für die Klasse bekannt, sondern auch ::A::A. Und ::A::A::A::A::A. und so weiter. Soweit zur "scheinbaren" Mehrdeutigkeit. Warum der Compiler da groß meckert wundert mich allerdings auch...
-
Im Scope einer Klasse A im globalen namespace ist also nicht nur das Symbol ::A für die Klasse bekannt, sondern auch ::A::A. Und ::A::A::A::A::A. und so weiter.
Das kann ich mit dem cl9.0 nicht nachvollziehen, wahrscheinlich weil ich es nicht richtig verstanden habe. Bei folgendem Code gibt der cl9.0 an den markierten Stellen einen Fehler aus:
class A { public: ::A *p1; // Ok ::A::A *p2; // Fehler }; int main(int argc, char* argv[]) { ::A a1; // Ok ::A::A a2; // Fehler }Im Gültigkeitsbereich der Klasse A ist also A und ::A (wobei A und ::A exakt das selbe ist) bekannt, nicht aber ::A::A (für den cl9.0). Weiter oben in der Diskussion haben wir aber gesehen, dass für den cl9.0 (wohl nicht für den gcc) aber eben A nicht gleich ::A ist. Das verwirrt mich etwas.
Bisher dachte ich nämlich, dass A und ::A exakt das selbe ist, weshalb ich bisher noch nie ::A verwendet habe, sondern immer A. Weiß jemand, für was das vorangestellte :: genau steht?
-
Weispfenning schrieb:
Im Scope einer Klasse A im globalen namespace ist also nicht nur das Symbol ::A für die Klasse bekannt, sondern auch ::A::A. Und ::A::A::A::A::A. und so weiter.
Das kann ich mit dem cl9.0 nicht nachvollziehen, wahrscheinlich weil ich es nicht richtig verstanden habe. Bei folgendem Code gibt der cl9.0 an den markierten Stellen einen Fehler aus:
class A { public: ::A *p1; // Ok ::A::A *p2; // Fehler }; int main(int argc, char* argv[]) { ::A a1; // Ok ::A::A a2; // Fehler }Im Gültigkeitsbereich der Klasse A ist also A und ::A (wobei A und ::A exakt das selbe ist) bekannt, nicht aber ::A::A (für den cl9.0). Weiter oben in der Diskussion haben wir aber gesehen, dass für den cl9.0 (wohl nicht für den gcc) aber eben A nicht gleich ::A ist. Das verwirrt mich etwas.
Bisher dachte ich nämlich, dass A und ::A exakt das selbe ist, weshalb ich bisher noch nie ::A verwendet habe, sondern immer A. Weiß jemand, für was das vorangestellte :: genau steht?
A und ::A sind dann gleich, wenn A selbst im globalen Namensraum deklariert wurde. A::A::A::A ist ein bisschen gemein zu demonstrieren, weil A::A je nach Kontext auch auf den Konstruktor verweisen kann. An den Stellen, an denen der Konstruktor gemeint sein könnte, verweist A::A dann auch darauf.
namespace foo { struct A { A(); }; A::A() {} // Verweist auf Konstruktor A::A::A a; // Fehler, A::A ist hier der Konstruktor, und kann nicht als Namensraumspezifikation benutzt werden struct A::A::A::A b; // ok, A::A kann hier nicht auf den Konstruktor verweisen struct ::A::A::A c; // Fehler, keine Entität A im globalen Namensraum struct foo::A::A::A d; // ok struct ::foo::A::A::A e; // ok struct B : A::A::A {}; // ok }
-
Das :: steht für den globalen Scope. Beispiel:
int irgendwas; void machWas() { int irgendwas = 2; ::irgendwas=irgendwas; //Setzt das Globale irgendwas auf den Wert vom lokalen irgendwas (2) }Nicht sehr sinvolles Beispiel, ich weiß.
-
Noch eine nicht ganz intuitive Kleinigkeit zu A::A
struct A { A(int) {} }; int main() { A(42); // ok function style cast -> Konstruktoraufruf A::A(42); // Fehler, A::A IST der Konstruktor und kann nicht direkt aufgerufen werden (A)10; // ok (A::A)10; // Fehler (struct A::A)10; // ok }
-
Das mit der Doppeldeutigkeit zwischen Konstruktor A::A und Klassenname A::A habe ich nun verstanden, danke! Zur Info, der cl9.0 scheint sich etwas anders zu verhalten, es ergeben sich für die zwei Beispiele von camper folgendes:
namespace foo { struct A { A(); }; A::A() {} A::A::A a; // Fehler: Das Symbol links neben "::" muss ein Typ sein. struct A::A::A::A b; // Fehler: Das Symbol links neben "::" muss ein Typ sein. struct ::A::A::A c; // Fehler: Das Symbol links neben "::" muss ein Typ sein. struct foo::A::A::A d; // Fehler: Das Symbol links neben "::" muss ein Typ sein. struct ::foo::A::A::A e; // Fehler: Das Symbol links neben "::" muss ein Typ sein. struct B : A::A::A {}; // Fehler: Das Symbol links neben "::" muss ein Typ sein. } struct A { A(int) {} }; int main() { A(42); // ok A::A(42); // KEIN Fehler!! (A)10; // ok (A::A)10; // Fehler: Syntaxfehler: Es fehlt ';' vor 'Konstante' (struct A::A)10; // Fehler: Ist kein Element von 'A' }Ich bin hiermit erstmal zufrieden, da die Beispiele mir ohnehin etwas praxisfern erscheinen. Nochmals danke an alle!