2014-07-01 16 views
5

Ich habe C++ - Templating gelernt und bin auf seltsames Verhalten gestoßen. Betrachten Sie diese Klassenstruktur (abgespeckte von meinem ursprünglichen Code):Zugriff auf geerbte Objekte aus der Klassenvorlage

class A { 
public: 
    std::vector <int> vec; 
}; 

template <typename T> class B : public A { }; 

template <typename T> class C : public B<T> { 
public: 
    using A::vec; 
    int test() { 
     return vec[1];  // OK 
    } 

    int test2() { 
     return vec.size(); // error: 'class A' has no member named 'size' 
    } 
}; 

Beim Kompilieren, erhalte ich einen Fehler in test2 und sagte, dass class Asize kein Mitglied hat. Aber vec sollte ein vector Objekt sein, keine Instanz von A. In der Tat, wenn ich C direkt von A anstelle von B<T> ableite oder die Vorlage von C entferne, kompiliert es fein.

Außerdem, wenn ich die folgende Methode C hinzufügen:

int test3() { 
    void ***v = vec;  // error: cannot convert from 
          // 'std::vector<int,...>' to 'void***' 
} 

die Compiler sagt es nicht von einem vector<int> zu void*** umwandeln kann, so dass es die richtige Art für vec zu wissen scheint. Mache ich hier einen Fehler, oder ist das möglicherweise ein Fehler in meinem Compiler? Ich benutze eine Apple-Version von g ++ 4.2.1. Edit: scheint auch in späteren Versionen von g ++ aufzutreten.

Danke für Ihre Hilfe!

Zweite bearbeiten: mein Compiler ist glücklich, wenn ich this->vec.size() in test2, anstatt sich auf die using A::vec Erklärung verwenden.

+0

[Warum muss ich Vorlage Basisklasse Mitglieder durch die diesen Zeiger zugreifen?] (Http://stackoverflow.com/ q/4643074/341970) – Ali

Antwort

2

Zuerst kompiliert Ihr Code mit clang (siehe here) und kompiliert nicht mit gcc. Ich habe es auch mit VS2013 kompilieren lassen.


Ihr ursprüngliches Problem bezieht sich darauf, wie der Compiler Namen in Schablonen sucht.

The Standard § 14.6.2:

Nicht-abhängige Namen in einer Template-Definition verwendet werden, finden die üblichen Namen-Suche verwenden und an dem Punkt, sie verwendet werden, gebunden.

Auch die C++ FAQ hat einen guten Eintrag über sie:

Der Compiler sieht nicht in den abhängigen Basisklassen (wie B), wenn nondependent Namen Nachschlagen (wie vec).


Lösung:

1. Verwenden this->vec (dies ist immer implizit abhängig in einer Vorlage)

int test2() { 
    return this->vec.size(); 
} 

2. Verwenden using B<T>::vec

3. Verwenden B<T> direkt:

int test2() { 
    return B<T>::vec.size(); 
} 

Hinweise:

  • Ich bin mir nicht sicher, warum gcc using A::vec; ablehnt, sieht aus wie ein Compiler Fehler zu mir (und beachten Sie, dass using B<T>::A::vec; Werke).
  • Standard-Referenz für die Lookup-Vorlagennamen: 14.6.3 und § 14.6.4
+0

Danke für Ihre Antwort! Ich habe schnell über das Problem mit nicht abhängigen Namen und abhängigen Basisklassen gelesen (und dort habe ich die Syntax 'using A :: vec' gelernt). Aber ich wusste nicht, dass Sie Scope-Resolution-Operatoren wie B :: A :: vec stacken können - das ist gut zu wissen. –

Verwandte Themen