Wofür steht der Typname offiziell?

Lesezeit: 7 Minuten

Wofur steht der Typname offiziell
dicroce

Gelegentlich habe ich einige wirklich nicht entzifferbare Fehlermeldungen gesehen, die von ausgespuckt wurden gcc bei der Verwendung von Vorlagen … Insbesondere hatte ich Probleme, bei denen scheinbar korrekte Deklarationen sehr seltsame Kompilierungsfehler verursachten, die auf magische Weise durch das Präfixieren von verschwanden typename Schlüsselwort an den Anfang der Deklaration … (Zum Beispiel habe ich erst letzte Woche zwei Iteratoren als Mitglieder einer anderen Schablonenklasse deklariert, und ich musste dies tun) …

Worum geht es in der Geschichte typename?

  • stackoverflow.com/questions/1600464

    – sbi

    21. Oktober 2009 um 17:12 Uhr

1646916608 12 Wofur steht der Typname offiziell
Naveen

Es folgt das Zitat aus Josuttis Buch:

Das Schlüsselwort typename wurde eingeführt, um anzugeben, dass der folgende Bezeichner ein Typ ist. Betrachten Sie das folgende Beispiel:

template <class T>
Class MyClass
{
  typename T::SubType * ptr;
  ...
};

Hier, typename wird verwendet, um das zu verdeutlichen
SubType ist eine Art von class T. Daher,
ptr ist ein Zeiger auf den Typ
T::SubType. Ohne typename, SubType
würde als statisches Mitglied betrachtet werden. Daher

T::SubType * ptr

wäre eine Vervielfachung des Wertes
SubType des Typs T mit ptr.

  • Tolles Buch. Lesen Sie es einmal durch und behalten Sie es als Referenz, wenn Sie möchten.

    – geschickt_code

    21. Oktober 2009 um 15:46 Uhr

  • Der aufmerksame Leser wird erkennen, dass ein Multiplikationsausdruck von der Grammatik für eine Mitgliedsdeklaration nicht erlaubt ist. Als solches C++20 verzichtet auf die Notwendigkeit dafür typename (wenn auch nicht alle!).

    – Davis Hering

    9. Mai 2019 um 3:52 Uhr


  • Hat mich nicht überzeugt. Sobald die Vorlage instanziiert ist, ist sehr gut definiert, was der T::Subtyp ist

    – Kovarex

    28. Juli 2020 um 18:47 Uhr

Wofur steht der Typname offiziell
Xinus

Stan Lippmans BLog-Beitrag schlägt vor :-

Ströstrup das vorhandene Schlüsselwort class wiederverwendet einen Typparameter anzugeben, anstatt ein neues Schlüsselwort einzuführen, das natürlich bestehende Programme beschädigen könnte. Es war nicht so, dass ein neues Schlüsselwort nicht in Betracht gezogen wurde – nur, dass es angesichts seiner potenziellen Störung nicht als notwendig erachtet wurde. Und Bis zum ISO-C++-Standard war dies die einzige Möglichkeit, einen Typparameter zu deklarieren.

Im Grunde genommen hat Stroustrup das Klassenschlüsselwort wiederverwendet, ohne ein neues Schlüsselwort einzuführen, das später im Standard aus den folgenden Gründen geändert wird

Wie das gegebene Beispiel

template <class T>
class Demonstration {
public:
void method() {
    T::A *aObj; // oops …
     // …
};

Sprachgrammatik missinterpretiert T::A *aObj; als arithmetischer Ausdruck wird also ein neues Schlüsselwort eingeführt genannt typename

typename T::A* a6;

es weist den Compiler an, die nachfolgende Anweisung als Deklaration zu behandeln.

Da das Schlüsselwort auf der Gehaltsliste stand, zum Teufel, warum die durch die ursprüngliche Entscheidung verursachte Verwirrung nicht beheben um das Klassenschlüsselwort wiederzuverwenden.

Deshalb haben wir beides

Kann man sich anschauen dieser Beitrages wird dir definitiv helfen, ich habe gerade so viel daraus extrahiert, wie ich konnte

  • Ja, aber warum war dann ein neues Schlüsselwort typename erforderlich, wenn Sie das vorhandene Schlüsselwort verwenden könnten class für den gleichen Zweck?

    – Jesper

    21. Oktober 2009 um 13:59 Uhr

  • @Jesper: Ich denke, die Antwort von Xenus ist hier verwirrend. typename wurde notwendig, um das Parsing-Problem zu beheben, wie in Naveens Antwort beschrieben, indem Josuttis zitiert wurde. (Ich glaube nicht, dass das Einfügen einer class an dieser Stelle hätte funktioniert.) Erst nachdem das neue Schlüsselwort für diesen Fall akzeptiert wurde, wurde es auch in Template-Argument-Deklarationen erlaubt (oder sind das Definitionen?), weil das class es war schon immer etwas irreführend.

    – sbi

    23. Oktober 2009 um 9:02 Uhr

Betrachten Sie den Code

template<class T> somefunction( T * arg )
{
    T::sometype x; // broken
    .
    .

Leider muss der Compiler kein Hellseher sein und weiß nicht, ob T::sometype am Ende auf einen Typnamen oder ein statisches Mitglied von T verweist. Also verwendet man typename um es zu sagen:

template<class T> somefunction( T * arg )
{
    typename T::sometype x; // works!
    .
    .

1646916609 49 Wofur steht der Typname offiziell
Ameise

In einigen Situationen, in denen Sie sich auf ein Mitglied so genannter beziehen abhängig type (bedeutet “abhängig von Template-Parameter”), kann der Compiler nicht immer eindeutig auf die semantische Bedeutung des resultierenden Konstrukts schließen, weil er nicht weiß, um was für einen Namen es sich handelt (also ob es sich um einen Namen eines Typs, einen Namen handelt eines Datenelements oder Name von etwas anderem). In solchen Fällen müssen Sie die Situation eindeutig machen, indem Sie dem Compiler explizit mitteilen, dass der Name zu einem Typnamen gehört, der als Mitglied dieses abhängigen Typs definiert ist.

Zum Beispiel

template <class T> struct S {
  typename T::type i;
};

In diesem Beispiel das Schlüsselwort typename erforderlich, damit der Code kompiliert werden kann.

Dasselbe passiert, wenn Sie auf ein Template-Member vom abhängigen Typ verweisen möchten, dh auf einen Namen, der ein Template bezeichnet. Sie müssen auch dem Compiler helfen, indem Sie das Schlüsselwort verwenden templateobwohl es anders platziert ist

template <class T> struct S {
  T::template ptr<int> p;
};

In einigen Fällen kann es erforderlich sein, beide zu verwenden

template <class T> struct S {
  typename T::template ptr<int>::type i;
};

(wenn ich die Syntax richtig verstanden habe).

Natürlich spielt das Schlüsselwort eine andere Rolle typename in Vorlagenparameterdeklarationen verwendet werden soll.

Das Geheimnis liegt darin, dass eine Vorlage für einige Typen spezialisiert werden kann. Das heißt, es kann auch die Schnittstelle für mehrere Typen völlig unterschiedlich definieren. Sie können zum Beispiel schreiben:

template<typename T>
struct test {
    typedef T* ptr;
};

template<>         // complete specialization 
struct test<int> { // for the case T is int
    T* ptr;
};

Man könnte sich fragen, warum das sinnvoll ist und in der Tat: Das sieht wirklich nutzlos aus. Aber denken Sie zum Beispiel daran std::vector<bool> der reference Typ sieht ganz anders aus als bei anderen TS. Zugegebenermaßen ändert es nichts an der Art reference von einem Typ zu etwas anderem, aber es könnte trotzdem passieren.

Was passiert nun, wenn Sie damit Ihre eigenen Vorlagen schreiben? test Vorlage. Etwas wie das

template<typename T>
void print(T& x) {
    test<T>::ptr p = &x;
    std::cout << *p << std::endl;
}

es scheint ok für dich zu sein, weil du erwarten das test<T>::ptr ist ein Typ. Aber der Compiler weiß es nicht, und tatsächlich wird ihm vom Standard sogar geraten, das Gegenteil zu erwarten, test<T>::ptr ist kein Typ. Um dem Compiler mitzuteilen, was Sie erwarten, müssen Sie a hinzufügen typename Vor. Die richtige Vorlage sieht so aus

template<typename T>
void print(T& x) {
    typename test<T>::ptr p = &x;
    std::cout << *p << std::endl;
}

Fazit: Sie müssen hinzufügen typename bevor Sie einen verschachtelten Vorlagentyp in Ihren Vorlagen verwenden. (Natürlich nur, wenn ein Template-Parameter Ihres Templates für dieses innere Template verwendet wird.)

Wofur steht der Typname offiziell
NAND

Zwei Verwendungen:

  1. Als ein template Argument-Schlüsselwort (anstelle von class)
  2. EIN typename Das Schlüsselwort teilt dem Compiler mit, dass ein Bezeichner ein Typ ist (und keine statische Elementvariable).
template <typename T> class X  // [1]
{
    typename T::Y _member;  // [2] 
}

Ich denke, alle Antworten haben erwähnt, dass die typename Schlüsselwort, wird in zwei verschiedenen Fällen verwendet:

a) Beim Deklarieren eines Vorlagentypparameters. z.B

template<class T> class MyClass{};        // these two cases are
template<typename T> class MyNewClass{};  // exactly the same.

Wobei es keinen Unterschied zwischen ihnen gibt und sie GENAU gleich sind.

b) Vor der Verwendung von a Name des verschachtelten abhängigen Typs für eine Vorlage.

template<class T>
void foo(const T & param)
{
   typename T::NestedType * value; // we should use typename here
}

Welche nicht verwenden typename führt zu Analyse-/Kompilierungsfehlern.

Was ich dem zweiten Fall hinzufügen möchte, wie er in Scot Meyers Buch Effective C++ erwähnt wird, ist, dass es eine Ausnahme von using gibt typename vor einem Name des verschachtelten abhängigen Typs. Die Ausnahme ist, wenn Sie die verwenden Name des verschachtelten abhängigen Typs entweder als Basisklasse oder in einem Member-Initialisierungslistesollten Sie nicht verwenden typename dort:

template<class T>
class D : public B<T>::NestedType               // No need for typename here
{
public:
   D(std::string str) : B<T>::NestedType(str)   // No need for typename here
   {
      typename B<T>::AnotherNestedType * x;     // typename is needed here
   }
}

Notiz: Verwenden typename für den zweiten Fall (dh vor dem verschachtelten abhängigen Typnamen) wird seit C++20 nicht mehr benötigt.

987980cookie-checkWofür steht der Typname offiziell?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy