wake-up-neo.com

Propagierung von 'typedef' von 'based' zu 'abgeleiteter Klasse' für 'template'

Ich versuche, eine Basisklasse zu definieren, die nur Typedefs enthält. 

template<typename T>
class A
{
public:
    typedef std::vector<T> Vec_t;
};


template<typename T>
class B : public A<T>
{
private:
    Vec_t v;  // fails - Vec_t is not recognized
};

Warum bekomme ich in B eine Fehlermeldung, dass Vec_t nicht erkannt wird und ich es explizit schreiben muss?

typename A<T>::Vec_t v;
54
dimba

Ich glaube, dass diese Frage doppelt ist, aber ich kann sie jetzt nicht finden. Laut C++ - Standard sollten Sie den Namen gemäß 14.6.2/3 vollständig qualifizieren:

Wenn bei der Definition einer Klassenvorlage oder eines Member einer Klassenvorlage eine Basisklasse der Klassenvorlage von einem Vorlagenparameter abhängt, wird der base-Klassenbereich während der unqualifizierten Namenssuche weder am Punkt noch überprüft Definition der Klassenvorlage oder des Mitglieds oder während einer Instantiierung der Klassenvorlage oder des Mitglieds.

UPD: Ich habe endlich ein Duplikat gefunden: hier ist es .

42

Bei Vorlagen gibt es so genannte abhängige und nicht abhängige Namen.

Wenn name vom Template-Parameter T abhängt, ist sein abhängiger Name und andere, die nicht von Parameter T abhängen, independent -Namen.

Hier ist die Regel: Der Compiler nicht suchen Sie in abhängigen Basisklassen (wie A), wenn Sie unabhängig voneinander suchen Namen (wie Vec_t). Als Ergebnis, der Compiler weiß gar nicht, dass existieren, geschweige denn Typen sind.

Der Compiler kann nicht annehmen, dass Vec_t ein Typ ist, bis er T kennt, da A<T> eine mögliche Spezialisierung enthält, wobei A<T>:: Vec_t ein Datenelement ist

Die Lösung ist also typename 

 typename A<T>::Vec_t v;  ← good

Ich empfehle Ihnen, diese https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-types durchzugehen.

Alter (defekter) Link: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.18

31
Xinus

Weil der Compiler nicht sicher ist, dass Vec_t einen Typ benennt. Beispielsweise könnte A<T> für T=int auf nicht diese bestimmte typedef spezialisiert sein.

7
Jesse Beder

Sie müssen die Verwendung von Vec_t explizit qualifizieren, da der Compiler nicht weiß, woher Vec_t kommt.

Es kann von der Struktur von A nichts ausgehen, da die Klassenvorlage A spezialisiert sein kann. Die Spezialisierung kann einen Vec_t enthalten, der kein Typedef ist, oder er kann überhaupt kein Mitglied Vec_t enthalten.

2
user200783

Der Vollständigkeit halber können Sie dieses Ärgernis ein wenig abschwächen:

  • geben Sie diese Typen in abgeleiteten Klassen erneut ein, oder besser - wie bei den Methoden von -
  • importieren Sie einfach diese Namen im abgeleiteten Klassenbereich mit einem using declaration:

template<typename T>
class A
{
public:
    typedef std::vector<T> Vec_t;
};


template<typename T>
class B : public A<T>
{
public:
    using typename A<T>::Vec_t;
    // .........

private:
    Vec_t v;
};

Dies kann nützlich sein, wenn Sie mehr als eine Erwähnung der geerbten typedef in der abgeleiteten Klasse haben. Außerdem müssen Sie nicht jedes Mal typename hinzufügen.

1
Roman Kruglov

Vec_t ist kein abhängiger Name, und der Compiler muss wissen, um was es sich handelt, ohne dass Schablonen (in diesem Fall die Basisklasse) instanziiert werden. Es unterscheidet sich wirklich nicht von:

template <class T>
class X
{
    std::string s;
}

Auch hier muss der Compiler über std :: string Bescheid wissen, auch wenn X nicht instanziiert wird, da der Name nicht vom Template-Argument T abhängt (soweit der Compiler annehmen kann).

Alles in allem scheinen Typedefs in einer Vorlagenbasisklasse für die Verwendung in abgeleiteten Klassen eher unbrauchbar zu sein. Die Typedefs sind jedoch für den Benutzer hilfreich. 

1
UncleBens

Dieses Konzept kann der Verwendung von std::vector<T> zugeordnet werden. Zum Beispiel, wenn wir einen std::vector<int> Foo haben. Jetzt entscheiden wir uns für einen beliebigen Mitgliedstyp, sagen wir eine iterator. In diesem Szenario wird ausdrücklich darauf hingewiesen

std::vector<int>::iterator foo_iterator;

In ähnlicher Weise müssen Sie in Ihrem Fall den öffentlichen Member-Typ Vec_t von template <typename T> class A explizit als deklarieren

A<T>::Vec_t v;
OR
A<int>::Vec_t int_type;
1
RAD