794 Stimmen

Unterschied zwischen den Schlüsselwörtern 'typename' und 'class' in Vorlagen?

Für Vorlagen habe ich beide Erklärungen gesehen:

template < typename T >
template < class T >

Was ist der Unterschied?

Und was genau bedeuten diese Schlüsselwörter in dem folgenden Beispiel (aus dem deutschen Wikipedia-Artikel über Vorlagen)?

template < template < typename, typename > class Container, typename Type >
class Example
{
     Container< Type, std::allocator < Type > > baz;
};

619voto

Aaron Klotz Punkte 10727

typename et class sind im Grundfall der Angabe einer Vorlage austauschbar:

template<class T>
class Foo
{
};

y

template<typename T>
class Foo
{
};

gleichwertig sind.

Es gibt jedoch bestimmte Fälle, in denen ein Unterschied besteht zwischen typename et class .

Der erste Fall betrifft die abhängigen Typen. typename wird verwendet, um zu deklarieren, wenn Sie auf einen verschachtelten Typ verweisen, der von einem anderen Vorlagenparameter abhängt, wie z. B. der typedef in diesem Beispiel:

template<typename param_t>
class Foo
{
    typedef typename param_t::baz sub_t;
};

Das zweite zeigen Sie in Ihrer Frage, auch wenn Sie es vielleicht nicht merken:

template < template < typename, typename > class Container, typename Type >

Bei der Angabe einer Vorlage Vorlage die class Schlüsselwort MUSS wie oben verwendet werden - es ist no austauschbar mit typename in diesem Fall (Hinweis: seit C++17 sind in diesem Fall beide Schlüsselwörter erlaubt) .

Sie müssen auch Folgendes verwenden class bei der expliziten Instanziierung einer Vorlage:

template class Foo<int>;

Ich bin sicher, dass es noch andere Fälle gibt, die ich übersehen habe, aber die Quintessenz ist: Diese beiden Schlüsselwörter sind nicht gleichwertig, und dies sind einige häufige Fälle, in denen Sie das eine oder das andere verwenden müssen.

75 Stimmen

Letzteres ist sozusagen ein Spezialfall der Tatsache, dass Sie class oder struct und nicht typename verwenden müssen, um eine Klasse zu definieren. Offensichtlich kann keines der ersten beiden Stücke Code durch die folgenden ersetzt werden template <typename T> typename Foo {}; denn Foo<T> ist ganz eindeutig eine Klasse.

3 Stimmen

std::vector<int>::value_type kein abhängiger Typ ist, brauchen Sie keine typename Sie brauchen sie nur, wenn ein Typ von einem Vorlagenparameter abhängt, zum Beispiel template<class T> struct C { typedef typename std::vector<T>::value_type type; };

2 Stimmen

Und wieder, param_t ist kein abhängiger Typ. Abhängige Typen sind Namen, die von einem Vorlagenparameter abhängig sind z.B. foo<param_t>::some_type und nicht die Vorlagenparameter selbst.

134voto

Georg Fritzsche Punkte 95256

Zur Benennung von Vorlagenparametern, typename et class gleichwertig sind. §14.1.2:

Es gibt keinen semantischen Unterschied zwischen class und typename in einem Vorlage-Parameter.

typename ist jedoch in einem anderen Zusammenhang bei der Verwendung von Schablonen möglich - als Hinweis für den Compiler, dass Sie sich auf einen abhängigen Typ beziehen. §14.6.2:

Ein Name, der in einer Schablonenerklärung verwendet wird oder einer Definition verwendet wird und der abhängig ist von einem Template-Parameter abhängt, wird angenommen, dass er keinen nicht als Name eines Typs, es sei denn, die entsprechende Namens Lookup einen Typnamen findet oder der Name ist durch das Schlüsselwort typename qualifiziert.

Beispiel:

typename some_template<T>::some_type

Ohne typename der Compiler kann im Allgemeinen nicht erkennen, ob Sie sich auf einen Typ beziehen oder nicht.

8 Stimmen

Ich verstehe die Regel, aber was genau hindert den Compiler daran, some_template<T> intern als einen Typ zu behandeln? Entschuldigung, wenn ich etwas Offensichtliches übersehe.

6 Stimmen

@batbrat Hier ist die ausführliche Antwort zu diesem Thema. Z.B., some_template<T>::something * p; kann eine Zeigerdeklaration oder eine Multiplikation sein.

0 Stimmen

Danke @AlexChe Ich werde mir den Link ansehen!

37voto

Michael Anderson Punkte 65535

Obwohl es keinen technischen Unterschied gibt, habe ich gesehen, dass die beiden Begriffe für leicht unterschiedliche Dinge verwendet werden.

Für eine Vorlage, die einen beliebigen Typ als T akzeptieren soll, einschließlich eingebauter Typen (wie z. B. ein Array)

template<typename T>
class Foo { ... }

Bei einer Vorlage funktioniert das nur, wenn T eine echte Klasse ist.

template<class T>
class Foo { ... }

Aber bedenken Sie, dass dies nur eine Frage des Stils ist, den manche Leute verwenden. Es wird nicht vom Standard vorgeschrieben oder von den Compilern erzwungen.

24 Stimmen

Ich nehme es Ihnen nicht übel, dass Sie es erwähnt haben, aber ich denke, dass diese Politik ziemlich fehlgeleitet ist, da Programmierer am Ende Zeit damit verbringen, über etwas nachzudenken, das keine Rolle spielt ("habe ich den richtigen verwendet?"), um etwas anzuzeigen, das keine Rolle spielt ("gibt es einen eingebauten Typ, der die für diesen Vorlagenparameter erforderliche Schnittstelle implementiert?"). Wenn irgendwelche Elemente des Template-Parameters verwendet werden ( T t; int i = t.toInt(); ), dann brauchen Sie eine "echte Klasse", und Ihr Code wird nicht kompiliert, wenn Sie int para T ...

1 Stimmen

Wenn Sie die Verwendung auf tatsächliche Klassen beschränken wollen, ist es besser, eine Spezialisierung hinzuzufügen, die einen Fehler für Nicht-Klassen-Typen auslöst oder verursacht. Wenn Sie die Verwendung auf bestimmte Klassen beschränken wollen, spezialisieren Sie nur für diese. In jedem Fall ist eine solche stilistische Unterscheidung zu subtil, um die Botschaft zu vermitteln.

4 Stimmen

Da sie das Gleiche bedeuten, verwenden Sie bitte nur einen. Andernfalls ist es so, als würden Sie inline { verwenden, es sei denn, es ist ein Dienstag, und dann verwenden Sie next-line {.

12voto

Nikolai Fetissov Punkte 79627
  1. Kein Unterschied
  2. Parameter für den Vorlagentyp Container ist selbst eine Vorlage mit zwei Typparametern.

4 Stimmen

Es gibt einen generellen Unterschied.

0 Stimmen

Könnten die beiden Parameter, mit denen der Container als Vorlage dient, auch benannt werden? im Beispiel haben sie keine Namen. Und außerdem - in diesem Beispiel steht 'class Container' - könnte man stattdessen auch 'typename Container' schreiben?

2 Stimmen

@Mat: Ja, der zu suchende Begriff ist vorlage vorlage parameter/argumente . Z.B.: template<template<class U> class V> struct C {};

9voto

Gurpreet Singh Punkte 61

Es gibt keinen Unterschied zwischen der Verwendung von <typename T> OU <class T> ; d.h. es ist eine Konvention, die von C++-Programmierern verwendet wird. Ich selbst bevorzuge <typename T> da sie die Verwendung klarer beschreibt, d. h. die Definition einer Vorlage mit einem bestimmten Typ.

Hinweis: Es gibt eine Ausnahme, bei der Sie Folgendes verwenden müssen class (und nicht typename ) bei der Deklaration eines Vorlagenparameters:

template <template <typename> class    T> class C { }; // valid!

template <template <typename> typename T> class C { }; // invalid!

In den meisten Fällen werden Sie keine verschachtelte Vorlagendefinition definieren, so dass beide Definitionen funktionieren - achten Sie nur auf eine konsistente Verwendung.

7 Stimmen

Beide Definitionen sind ab C++17 gültig

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X