2014-07-01 12 views
5

Uczyłem się szablonowania w C++ i przeszedłem przez jakieś dziwne zachowanie. Rozważmy tę strukturę klasy (uproszczoną z mojego oryginalnego kodu):Uzyskiwanie dostępu do dziedziczonych obiektów z szablonu klasy

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' 
    } 
}; 

Podczas kompilacji, pojawia się błąd w test2, mówiąc, że class A ma człon size. Ale vec powinien być obiektem vector, a nie instancją A. Rzeczywiście, jeśli wyprowadzę C bezpośrednio z A zamiast B<T>, lub usuń szablon z C, kompiluje się dobrze.

Ponadto, jeśli dodać następującą metodę C:

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

kompilator mówi, że nie można przekonwertować z vector<int> do void***, więc wydaje się znać właściwy typ dla vec. Czy popełniam tu błąd, czy może jest to błąd w moim kompilatorze? Używam wersji g ++ 4.2.1 Apple. Edycja: wydaje się również występować w późniejszych wersjach g ++.

Dzięki za pomoc!

Druga edycja: mój kompilator jest szczęśliwy, jeśli mogę użyć this->vec.size() w test2 zamiast opierania się na deklaracji using A::vec.

+0

[Dlaczego mam dostęp do szablonów członków klasy bazowej za pośrednictwem tego wskaźnika?] (Http://stackoverflow.com/ q/4643074/341970) – Ali

Odpowiedz

2

Po pierwsze, twój kod kompiluje się z klangiem (patrz: here) i nie kompiluje się z gcc. Dostałem go również do kompilacji z VS2013.


Twój pierwotny problem jest związany z tym, jak nazwy odnośników kompilatora w szablonach.

Standard § 14.6.2:

nazwy dla zależne użyte w definicji szablonu znajdują się używając zwykle wyszukiwanie nazw i związany w miejscu ich użycia.

Również C++ FAQ ma dobrą pozycję o tym:

Kompilator nie wygląda w utrzymaniu klas bazowych (jak b) gdy patrząc nazwy nondependent (jak vec).


Rozwiązanie:

1. Zastosowanie this->vec (jest to zawsze pośrednio zależna w szablonie)

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

2. Zastosowanie using B<T>::vec

3. Zastosowanie B<T> bezpośrednio:

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

Uwagi:

  • Nie jestem pewien, dlaczego gcc odmawia using A::vec;, wygląda jak błąd kompilatora do mnie (i zauważ, że using B<T>::A::vec; prace).
  • standard odniesienia do nazwy szablonu odnośnika: § 14.6.3 oraz § 14.6.4
+0

Dzięki za odpowiedź! Przeczytałem szybko o problemie z niezrzeszonymi nazwami i zależnymi klasami podstawowymi (i tam właśnie nauczyłem się składnia "używając A :: vec"). Ale, nie wiedziałem, że możesz umieścić operatorów rozdzielczości zakresu, takich jak B :: A :: vec - to dobrze wiedzieć. –

Powiązane problemy