Vorlagenabzugsleitfäden sind Muster, die einer Vorlagenklasse zugeordnet sind und dem Compiler mitteilen, wie eine Reihe von Konstruktorargumenten (und ihre Typen) in Vorlagenparameter für die Klasse übersetzt werden sollen.
Das einfachste Beispiel ist das von std::vector
und sein Konstruktor, der ein Iteratorpaar verwendet.
template<typename Iterator>
void func(Iterator first, Iterator last)
{
vector v(first, last);
}
Der Compiler muss , um herauszufinden , was vector<T>
‚s T
Art sein wird. Wir wissen, was die Antwort ist; T
sollte sein typename std::iterator_traits<Iterator>::value_type
. Aber wie können wir dem Compiler mitteilen, ohne tippen zu müssen?vector<typename std::iterator_traits<Iterator>::value_type>
?
Sie verwenden einen Abzugsleitfaden:
template<typename Iterator> vector(Iterator b, Iterator e) ->
vector<typename std::iterator_traits<Iterator>::value_type>;
Dies teilt dem Compiler mit, dass beim Aufrufen eines vector
Konstruktors, der diesem Muster entspricht, die vector
Spezialisierung mithilfe des Codes rechts von abgeleitet wird->
.
Sie benötigen Hilfslinien, wenn der Abzug des Typs von den Argumenten nicht auf dem Typ eines dieser Argumente basiert. Beim Initialisieren von a vector
von wird initializer_list
explizit das vector
's verwendetT
, sodass keine Anleitung erforderlich ist.
Die linke Seite gibt nicht unbedingt einen tatsächlichen Konstruktor an. Wenn Sie die Ableitung von Vorlagenkonstruktoren für einen Typ verwenden, stimmt dies mit den Argumenten überein, die Sie für alle Abzugsleitfäden übergeben (tatsächliche Konstruktoren der primären Vorlage bieten implizite Hilfslinien). Wenn es eine Übereinstimmung gibt, wird diese verwendet, um zu bestimmen, welche Vorlagenargumente für den Typ bereitgestellt werden sollen.
Sobald dieser Abzug erfolgt ist und der Compiler die Vorlagenparameter für den Typ ermittelt hat, erfolgt die Initialisierung für das Objekt dieses Typs so, als ob nichts davon geschehen wäre. Das heißt, der ausgewählte Abzugsleitfaden muss nicht mit dem ausgewählten Konstruktor übereinstimmen .
Dies bedeutet auch, dass Sie Hilfslinien mit Aggregaten und Aggregatinitialisierung verwenden können:
template<typename T>
struct Thingy
{
T t;
};
Thingy(const char *) -> Thingy<std::string>;
Thingy thing{"A String"}; //thing.t is a `std::string`.
Abzugsleitfäden werden daher nur verwendet, um den zu initialisierenden Typ herauszufinden. Sobald diese Feststellung getroffen wurde, funktioniert der eigentliche Initialisierungsprozess genauso wie zuvor.