
Anspruch
Ich weiß, dass wir in C++11 jetzt verwenden können using
Typ Alias zu schreiben, wie typedef
S:
typedef int MyInt;
Ist nach meinem Verständnis gleichbedeutend mit:
using MyInt = int;
Und diese neue Syntax entstand aus den Bemühungen, eine Möglichkeit zu haben, “Template Typedef” auszudrücken:
template< class T > using MyType = AnotherType< T, MyAllocatorType >;
Aber gibt es bei den ersten beiden Nicht-Template-Beispielen weitere subtile Unterschiede im Standard? Zum Beispiel, typedef
s machen Aliasing auf “schwache” Weise. Das heißt, es wird kein neuer Typ erstellt, sondern nur ein neuer Name (Konvertierungen sind zwischen diesen Namen implizit).
Ist es das gleiche mit using
oder generiert es einen neuen Typ? Gibt es Unterschiede?
Sie sind äquivalent, aus dem Standard (Hervorhebung von mir) (7.1.3.2):
Ein Typedef-Name kann auch durch eine Alias-Deklaration eingeleitet werden. Der Bezeichner nach dem Schlüsselwort using wird zu einem Typedef-Namen, und der optionale Attributbezeichner-seq nach dem Bezeichner gehört zu diesem Typedef-Namen. Es hat dieselbe Semantik, als ob es durch den typedef-Spezifizierer eingeführt worden wäre. Insbesondere definiert es keinen neuen Typ und erscheint nicht in der Typ-ID.

Zhongming Qu
Sie sind weitgehend gleich, außer dass:
Die Alias-Deklaration ist mit Templates kompatibel, die Typedef im C-Stil hingegen nicht.

4xy
Die verwenden Syntax hat einen Vorteil, wenn sie innerhalb von Vorlagen verwendet wird. Wenn Sie die Typabstraktion benötigen, müssen aber auch Vorlagenparameter beibehalten werden, damit sie in Zukunft angegeben werden können. Du solltest so etwas schreiben.
template <typename T> struct whatever {};
template <typename T> struct rebind
{
typedef whatever<T> type; // to make it possible to substitue the whatever in future.
};
rebind<int>::type variable;
template <typename U> struct bar { typename rebind<U>::type _var_member; }
Aber verwenden Syntax vereinfacht diesen Anwendungsfall.
template <typename T> using my_type = whatever<T>;
my_type<int> variable;
template <typename U> struct baz { my_type<U> _var_member; }

dfrib
Alle nachstehenden Standardreferenzen beziehen sich auf N4659: März 2017 Post-Kona-Arbeitsentwurf/C++17 DIS.
Typedef-Deklarationen können dies, während Alias-Deklarationen dies nicht können(+)als Initialisierungsanweisungen verwendet werden
Aber gibt es bei den ersten beiden Nicht-Template-Beispielen weitere subtile Unterschiede im Standard?
- Unterschiede in Semantik: keiner.
- Unterschiede in zulässigen Kontexten: etwas(++).
(+) P2360R0 (Erweitern Sie die Init-Anweisung, um die Alias-Deklaration zuzulassen) wurde von CWG genehmigt und ab C++23 wurde diese Inkonsistenz zwischen Typedef-Deklarationen und Alias-Deklarationen entfernt.
(++) Zusätzlich zu den Beispielen von Alias-Vorlagenwas bereits im ursprünglichen Beitrag erwähnt wurde.
Gleiche Semantik
Wie geregelt durch [dcl.typedef]/2 [extract, emphasis mine]
[dcl.typedef]/2 EIN
typedef-name
kann auch durch ein eingeleitet werden
Alias-Deklaration. Die Kennung nach dem using
Schlüsselwort wird zu a
typedef-name und das fakultative Attribut-Spezifizierer-Seq nach dem Kennung gehört dazu typedef-name. So ein
typedef-name hat dieselbe Semantik, als ob sie durch die eingeführt worden wäre typedef
Bezeichner. […]
ein typedef-name eingeführt von einem Alias-Deklaration hat die gleiche Semantik als ob es von der eingeführt wurde typedef
Erklärung.
Subtiler Unterschied in zulässigen Kontexten
Dies gilt jedoch nicht implizieren, dass die beiden Variationen die gleichen Einschränkungen in Bezug auf haben die Kontexte in denen sie verwendet werden dürfen. Und tatsächlich, wenn auch ein Eckfall, a typedef-Deklaration ist ein init-Anweisung und kann daher in Kontexten verwendet werden, die Initialisierungsanweisungen zulassen
// C++11 (C++03) (init. statement in for loop iteration statements).
for (typedef int Foo; Foo{} != 0;)
// ^^^^^^^^^^^^^^^ init-statement
{
}
// C++17 (if and switch initialization statements).
if (typedef int Foo; true)
// ^^^^^^^^^^^^^^^ init-statement
{
(void)Foo{};
}
switch (typedef int Foo; 0)
// ^^^^^^^^^^^^^^^ init-statement
{
case 0: (void)Foo{};
}
// C++20 (range-based for loop initialization statements).
std::vector<int> v{1, 2, 3};
for (typedef int Foo; Foo f : v)
// ^^^^^^^^^^^^^^^ init-statement
{
(void)f;
}
for (typedef struct { int x; int y;} P; auto [x, y] : {P{1, 1}, {1, 2}, {3, 5}})
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ init-statement
{
(void)x;
(void)y;
}
während ein Alias-Deklaration ist nicht ein init-Anweisungund somit nicht dürfen in Kontexten verwendet werden, die Initialisierungsanweisungen zulassen
// C++ 11.
for (using Foo = int; Foo{} != 0;) {}
// ^^^^^^^^^^^^^^^ error: expected expression
// C++17 (initialization expressions in switch and if statements).
if (using Foo = int; true) { (void)Foo{}; }
// ^^^^^^^^^^^^^^^ error: expected expression
switch (using Foo = int; 0) { case 0: (void)Foo{}; }
// ^^^^^^^^^^^^^^^ error: expected expression
// C++20 (range-based for loop initialization statements).
std::vector<int> v{1, 2, 3};
for (using Foo = int; Foo f : v) { (void)f; }
// ^^^^^^^^^^^^^^^ error: expected expression
Sie sind im Wesentlichen gleich, aber using
bietet alias templates
was ganz nützlich ist. Ein gutes Beispiel, das ich finden konnte, ist wie folgt:
namespace std {
template<typename T> using add_const_t = typename add_const<T>::type;
}
Also können wir verwenden std::add_const_t<T>
anstatt typename std::add_const<T>::type

Roboterwald
Ich weiß, dass das Originalposter eine großartige Antwort hat, aber für alle, die wie ich über diesen Thread stolpern, gibt es einen wichtigen Hinweis von der Antrag das meiner Meinung nach etwas Wertvolles zur Diskussion hier hinzufügt, insbesondere zu den Bedenken in den Kommentaren darüber, ob die typedef
Schlüsselwort wird in Zukunft als veraltet markiert oder entfernt, weil es redundant/alt ist:
Es wurde vorgeschlagen, das Schlüsselwort typedef … (wieder) zu verwenden, um Template-Aliase einzuführen:
template<class T>
typedef std::vector<T, MyAllocator<T> > Vec;
Diese Notation hat den Vorteil, dass ein bereits bekanntes Schlüsselwort verwendet wird, um einen Typenalias einzuführen. Allerdings weist es auch einige Nachteile auf [sic] darunter die Verwirrung bei der Verwendung eines Schlüsselworts, von dem bekannt ist, dass es einen Alias für einen Typnamen in einem Kontext einführt, in dem der Alias keinen Typ, sondern eine Vorlage bezeichnet; Vec
ist nicht ein Alias für einen Typ und sollte nicht für einen Typedef-Namen genommen werden. Der Name Vec
ist ein Name für die Familie std::vector<•, MyAllocator<•> >
– wobei das Aufzählungszeichen ein Platzhalter für einen Typnamen ist. Folglich schlagen wir nicht die „typedef“-Syntax vor. Andererseits wird der Satz
template<class T>
using Vec = std::vector<T, MyAllocator<T> >;
kann gelesen/interpretiert werden als: ab jetzt verwende ich Vec<T>
als Synonym für std::vector<T, MyAllocator<T> >
. Mit dieser Lektüre erscheint die neue Syntax für Aliasing einigermaßen logisch.
Für mich impliziert dies eine fortgesetzte Unterstützung für die typedef
Schlüsselwort in C++, weil es noch mehr Code machen kann lesbar und verständlich.
Aktualisieren der using
Schlüsselwort war speziell für Vorlagen und (wie in der akzeptierten Antwort darauf hingewiesen wurde) wenn Sie mit Nicht-Vorlagen arbeiten using
und typedef
sind mechanisch identisch, so dass die Wahl aus Gründen der Lesbarkeit und der Mitteilung der Absicht vollständig dem Programmierer überlassen bleibt.

marski
Beide Schlüsselwörter sind gleichwertig, es gibt jedoch einige Einschränkungen. Eine davon ist die Deklaration eines Funktionszeigers mit using T = int (*)(int, int);
ist klarer als mit typedef int (*T)(int, int);
. Zweitens ist das Template-Alias-Formular nicht möglich typedef
. Drittens würde das Offenlegen der C-API erforderlich sein typedef
in öffentlichen Kopfzeilen.
9961300cookie-checkWas ist der Unterschied zwischen „typedef“ und „using“ in C++11?yes
Ich persönlich bevorzuge die neue Syntax, weil sie der regulären Variablenzuweisung viel ähnlicher ist und die Lesbarkeit verbessert. Bevorzugen Sie zum Beispiel
typedef void (&MyFunc)(int,int);
oderusing MyFunc = void(int,int);
?– Matthias M.
25. Mai 2012 um 8:08 Uhr
Ich stimme voll und ganz zu, ich verwende jetzt nur noch die neue Syntax. Deshalb habe ich gefragt, um sicherzugehen, dass es wirklich keinen Unterschied gibt.
– Anspruch
25. Mai 2012 um 8:21 Uhr
@MatthieuM. die beiden sind übrigens unterschiedlich. Es sollte sein
typedef void MyFunc(int,int);
(was eigentlich gar nicht so schlecht aussieht), bzwusing MyFunc = void(&)(int,int);
– R.Martinho Fernandes
25. Mai 2012 um 14:28 Uhr
@R.MartinhoFernandes warum brauchst du (&) in
using MyFunc = void(&)(int,int);
? Bedeutet dasMyFunc
ist ein Verweis auf eine Funktion? Was ist, wenn Sie die weglassen &?– Reich
15. Juli 2015 um 4:50 Uhr
Ja, es ist eine Funktionsreferenz. Es ist gleichbedeutend mit
typedef void (&MyFunc)(int,int);
. Wenn Sie die weglassen&
es ist äquivalent zutypedef void MyFunc(int,int);
– R.Martinho Fernandes
15. Juli 2015 um 12:24 Uhr