Vorlagen-Metaprogrammierung
typedef
ist für viele Metaprogrammieraufgaben für Vorlagen erforderlich. Wenn eine Klasse als "Typfunktion zur Kompilierungszeit" behandelt wird, wird a als "Typwert zur Kompilierungszeit" verwendet, um den resultierenden Typ zu erhalten. Betrachten Sie beispielsweise eine einfache Metafunktion zum Konvertieren eines Zeigertyps in seinen Basistyp:typedef
template<typename T>
struct strip_pointer_from;
template<typename T>
struct strip_pointer_from<T*> {
typedef T type;
};
Beispiel: Der Typausdruck wird als strip_pointer_from<double*>::type
ausgewertet double
. Beachten Sie, dass die Metaprogrammierung von Vorlagen außerhalb der Bibliotheksentwicklung nicht häufig verwendet wird.
Vereinfachung der Funktionszeigertypen
typedef
ist hilfreich , um komplizierten Funktionszeigertypen einen kurzen, scharfen Alias zu geben:
typedef int (*my_callback_function_type)(int, double, std::string);
void RegisterCallback(my_callback_function_type fn) {
...
}
In Bjarnes Buch heißt es, dass Sie typedef verwenden können, um Portabilitätsprobleme zwischen Systemen mit unterschiedlichen Ganzzahlgrößen zu lösen. (Dies ist eine Paraphrase)
Auf einer Maschine mit
sizeof(int)
4 können Sietypedef int int32;
Dann
int32
überall in Ihrem Code verwenden. Wenn Sie zu einer Implementierung von C ++ mitsizeof(int)
2 wechseln, können Sie einfach die änderntypdef
typedef long int32;
und Ihr Programm wird weiterhin an der neuen Implementierung arbeiten.
quelle
Verwendung mit Funktionszeiger
Funktionszeigerdeklarationen ausblenden Mit einem typedef
void (*p[10]) (void (*)() );
Nur wenige Programmierer können erkennen, dass p ein "Array von 10 Zeigern auf eine Funktion ist, die void zurückgibt, und einen Zeiger auf eine andere Funktion, die void zurückgibt und keine Argumente akzeptiert." Die umständliche Syntax ist nahezu nicht zu entziffern. Sie können es jedoch erheblich vereinfachen, indem Sie typedef-Deklarationen verwenden. Deklarieren Sie zunächst ein typedef für "Zeiger auf eine Funktion, die void zurückgibt und keine Argumente akzeptiert" wie folgt:
typedef void (*pfv)();
Als nächstes deklarieren Sie ein anderes typedef für "Zeiger auf eine Funktion, die void zurückgibt und ein pfv nimmt" basierend auf dem zuvor deklarierten typedef:
typedef void (*pf_taking_pfv) (pfv);
Nachdem wir nun den pf_taking_pfv-Typedef als Synonym für den unhandlichen "Zeiger auf eine Funktion erstellt haben, die void zurückgibt und einen pfv nimmt", ist es ein Kinderspiel, ein Array von 10 solcher Zeiger zu deklarieren:
pf_taking_pfv p[10];
von
quelle
Nur um einige Beispiele für die genannten Dinge zu nennen: STL-Container.
typedef std::map<int,Froboz> tFrobozMap; tFrobozMap frobozzes; ... for(tFrobozMap::iterator it=frobozzes.begin(); it!=map.end(); ++it) { ... }
Es ist nicht ungewöhnlich, auch nur typedefs wie zu verwenden
typedef tFrobozMap::iterator tFrobozMapIter; typedef tFrobozMap::const_iterator tFrobozMapCIter;
Ein weiteres Beispiel: Verwenden gemeinsamer Zeiger:
class Froboz; typedef boost::shared_ptr<Froboz> FrobozPtr;
[Update] Laut Kommentar - wo sollen sie abgelegt werden?
Das letzte Beispiel - Verwenden
shared_ptr
- ist einfach: Sind echtes Header-Material - oder zumindest ein Forward-Header. Sie benötigen die Vorwärtsdeklaration für shared_ptr ohnehin, und einer der deklarierten Vorteile besteht darin, dass die Verwendung mit einer Vorwärtsdeklaration sicher ist.Anders ausgedrückt: Wenn es einen shared_ptr gibt, sollten Sie den Typ wahrscheinlich nur über einen shared_ptr verwenden, sodass das Trennen der Deklarationen wenig Sinn macht.
(Ja, xyzfwd.h ist ein Schmerz. Ich würde sie nur in Hotspots verwenden - in dem Wissen, dass Hotspots schwer zu identifizieren sind. Beschuldigen Sie das C ++ - Kompilierungs- + Linkmodell ...)
Containertypedefs verwende ich normalerweise dort, wo die Containervariable deklariert ist - z. B. lokal für eine lokale Variable, als Klassenmitglieder, wenn die tatsächliche Containerinstanz ein Klassenmitglied ist. Dies funktioniert gut, wenn der tatsächliche Containertyp ein Implementierungsdetail ist und keine zusätzliche Abhängigkeit verursacht.
Wenn sie Teil einer bestimmten Schnittstelle werden, werden sie zusammen mit der Schnittstelle deklariert, mit der sie verwendet werden, z
// FrobozMangler.h #include "Froboz.h" typedef std::map<int, Froboz> tFrobozMap; void Mangle(tFrobozMap const & frobozzes);
Dies wird problematisch, wenn der Typ ein Bindungselement zwischen verschiedenen Schnittstellen ist - dh der gleiche Typ wird von mehreren Headern benötigt. Einige Lösungen:
Ich bin damit einverstanden, dass die beiden letzteren nicht so toll sind, ich würde sie nur verwenden, wenn ich in Schwierigkeiten gerate (nicht proaktiv).
quelle
typedef ist in vielen Situationen nützlich.
Grundsätzlich können Sie einen Alias für einen Typ erstellen. Wenn Sie den Typ ändern müssen, kann der Rest des Codes unverändert bleiben (dies hängt natürlich vom Code ab). Angenommen, Sie möchten einen C ++ - Vektor iterieren
vector<int> v; ... for(vector<int>::const_iterator i = v->begin(); i != v.end(); i++) { // Stuff here }
In Zukunft könnten Sie daran denken, den Vektor mit einer Liste zu ändern, da die Art der Operationen, die Sie darauf ausführen müssen. Ohne typedef müssen Sie ALLE Vektorvorkommen in Ihrem Code ändern. Aber wenn Sie so etwas schreiben:
typedef vector<int> my_vect; my_vect v; ... for(my_vect::const_iterator i = v->begin(); i != v.end(); i++) { // Stuff here }
Jetzt müssen Sie nur noch eine Codezeile ändern (dh von "
typedef vector<int> my_vect
" nach "typedef list<int> my_vect
") und alles funktioniert.typedef spart Ihnen auch Zeit, wenn Sie komplexe Datenstrukturen haben, die sehr lang zu schreiben (und schwer zu lesen) sind.
quelle
Ein guter Grund, typedef zu verwenden, ist, wenn sich der Typ von etwas ändern kann. Angenommen, 16-Bit-Ints eignen sich derzeit für die Indizierung eines Datasets, da Sie auf absehbare Zeit weniger als 65535 Elemente haben und die Speicherplatzbeschränkungen erheblich sind oder eine gute Cache-Leistung erforderlich sind. Wenn Sie Ihr Programm jedoch nicht für ein Dataset mit mehr als 65535 Elementen verwenden müssen, möchten Sie problemlos zu einer breiteren Ganzzahl wechseln können. Verwenden Sie ein typedef, und Sie müssen dies nur an einer Stelle ändern.
quelle
typedef
Ermöglicht nicht nur einen Alias für komplexe Typen, sondern bietet Ihnen auch einen natürlichen Ort zum Dokumentieren eines Typs. Ich benutze es manchmal zu Dokumentationszwecken.Es gibt auch Zeiten, in denen ich ein Array von Bytes verwende. Jetzt könnte ein Array von Bytes eine Menge Dinge bedeuten.
typedef
macht es praktisch, mein Byte-Array als "hash32" oder "fileContent" zu definieren, um meinen Code besser lesbar zu machen.quelle
Reale Verwendung von typedef:
Bereitstellung lokaler Bezeichnungen für Typen, z.
template<class _T> class A { typedef _T T; }; template<class _T> class B { void doStuff( _T::T _value ); };
quelle
Es gibt einen anderen Anwendungsfall für die Verwendung von typedef, wenn wir eine Art containerunabhängigen Code aktivieren möchten (aber nicht genau!).
Nehmen wir an, Sie haben Unterricht:
Class CustomerList{ public: //some function private: typedef list<Customer> CustomerContainer; typedef CustomerContainer::iterator Cciterator; };
Der obige Code kapselt die interne Containerimplementierung mit typedef, und selbst wenn der Listencontainer in Zukunft in Vektor oder Deque geändert werden muss, muss sich der Benutzer der CustomerList-Klasse nicht um die genaue Containerimplementierung kümmern.
Daher kapselt das typedef und hilft uns etwas beim Schreiben von containerunabhängigem Code
quelle
Wann immer es die Quelle klarer oder besser lesbar macht.
Ich verwende eine Art typedef in C # für Generika / Vorlagen. Ein "NodeMapping" ist einfach besser zu lesen / zu verwenden und zu verstehen als viel "Dictionary <string, XmlNode>". MEINER BESCHEIDENEN MEINUNG NACH. Daher würde ich es für Vorlagen empfehlen.
quelle
Typedef ermöglicht Flexibilität in Ihrer Klasse. Wenn Sie den Datentyp im Programm ändern möchten, müssen Sie nicht mehrere Speicherorte ändern, sondern nur ein Vorkommen.
typedef <datatype example int or double> value_type
Sie können stattdessen einen Namen angeben
value_type
, diesvalue_type
ist jedoch normalerweise der Standardname.Sie können also typedef like verwenden
value_type i=0; //same as a int or double i=0;
quelle
... und Sie brauchen kein Typedef für eine Aufzählung oder eine Struktur.
Oder tust du?
typedef enum { c1, c2 } tMyEnum; typedef struct { int i; double d; } tMyStruct;
kann besser geschrieben werden als
enum tMyEnum { c1, c2 } struct tMyStruct { int i; double d; };
Ist das korrekt? Was ist mit C?
quelle