wake-up-neo.com

Was sind Vorlagenabzugshilfen und wann sollten wir sie verwenden?

Der C++ 17-Standard führt "Vorlagenableitungsrichtlinien" ein. Ich habe festgestellt, dass sie etwas mit dem neuen Template-Argument-Abzug für Konstruktoren zu tun haben, der in dieser Version des Standards eingeführt wurde, aber ich habe noch keine einfache Erklärung im FAQ-Stil gesehen, was sie sind und wofür sie gedacht sind.

  • Was sind Vorlagenableitungshandbücher in C++ 17?

  • Warum (und wann) brauchen wir sie?

  • Wie erkläre ich sie?

76
Tristan Brindle

Vorlagenableitungshilfslinien sind Muster, die einer Vorlagenklasse zugeordnet sind und dem Compiler mitteilen, wie eine Reihe von Parametern (und ihre Typen) in Vorlagenargumente übersetzt werden sollen.

Das einfachste Beispiel ist das von std::vector Und seinem Konstruktor, der ein Iteratorpaar akzeptiert.

template<typename Iterator>
void func(Iterator first, Iterator last)
{
  vector v(first, last);
}

Der Compiler muss herausfinden, welcher Typ vector<T>T sein wird. Wir wissen, wie die Antwort lautet. T sollte typename std::iterator_traits<Iterator>::value_type sein. Aber wie sagen wir dem Compiler ohne, dass er vector<typename std::iterator_traits<Iterator>::value_type> Eingeben muss?

Sie verwenden eine Abzugshilfe:

template<typename Iterator> vector(Iterator b, Iterator e) -> 
    vector<typename std::iterator_traits<Iterator>::value_type>;

Dies teilt dem Compiler mit, dass, wenn Sie einen vector -Konstruktor aufrufen, der diesem Muster entspricht, die vector -Spezialisierung unter Verwendung 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. Das Initialisieren eines vector aus einem initializer_list Verwendet explizit das vector des T, sodass keine Anleitung erforderlich ist.

Auf der linken Seite muss nicht unbedingt ein Konstruktor angegeben sein. Die Funktionsweise besteht darin, dass, wenn Sie die Vorlagenkonstruktorableitung für einen Typ verwenden, diese mit den Argumenten übereinstimmt, die Sie für alle Ableitungshilfslinien übergeben (die tatsächlichen Konstruktoren der primären Vorlage stellen implizite Hilfslinien bereit). Wenn eine Übereinstimmung vorliegt, wird anhand dieser ermittelt, welche Vorlagenargumente dem Typ zur Verfügung gestellt werden sollen.

Sobald dieser Abzug erfolgt ist und der Compiler die Vorlagenparameter für den Typ ermittelt hat, wird die Initialisierung für das Objekt dieses Typs fortgesetzt, als ob nichts davon geschehen wäre. Das heißt, die ausgewählte Abzugsrichtlinie 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`.

Abzugshilfen werden daher nur verwendet, um den zu initialisierenden Typ zu ermitteln. Der eigentliche Initialisierungsprozess funktioniert genau so wie zuvor, sobald diese Bestimmung vorgenommen wurde.

88
Nicol Bolas