2014-01-10 7 views
41

C++ 14 ermöglicht die Erstellung von Variablen, die Vorlagen sind. Das übliche Beispiel ist ein Variable ‚pi‘, die gelesen werden können, um den Wert der mathematischen Konstante π für verschiedene Arten zu erhalten (3 für int; der nächste Wert möglich mit float, etc.)C++ 14 Variable Vorlagen: Was ist ihr Zweck? Irgendein Anwendungsbeispiel?

Außer, dass wir dies haben können Feature nur durch das Umschließen einer Variablen innerhalb einer Template-Struktur oder Klasse, wie mischt sich dies mit Typkonvertierungen? Ich sehe Überschneidungen.

Und anders als das Pi-Beispiel, wie würde es mit nicht-const Variablen arbeiten? Ein Anwendungsbeispiel, um zu verstehen, wie man eine solche Funktion optimal nutzt und welchen Zweck sie hat?

+21

Der Vorschlag [N3651] (http://isocpp.org/files/papers/N3651.pdf) scheint viele dieser Informationen zu erfassen. –

Antwort

19

Und anders als das Pi Beispiel, wie würde es mit nicht-const Variablen funktionieren?

Derzeit scheint es die Variablen für den Typ getrennt zu instanziieren. das heißt, Sie könnten 10 zu n<int> zuweisen und es würde sich von der Vorlagendefinition unterscheiden.

template<typename T> 
T n = T(5); 

int main() 
{ 
    n<int> = 10; 
    std::cout << n<int> << " "; // 10 
    std::cout << n<double> << " "; // 5 
} 

Wenn die Deklaration const lautet, wird sie nur gelesen. Wenn es ein constexpr ist, wie alle constexpr Deklarationen, hat es nicht viel außerhalb constexpr (Resessions).

Abgesehen, dass wir diese Funktion nur durch eine variable Einwickeln in einer Templat-Struktur oder Klasse haben können, wie funktioniert diese Mischung mit Typ Conversions?

Es soll ein einfacher Vorschlag sein. Ich bin nicht in der Lage zu sehen, wie es sich auf Typkonvertierungen in signifikanter Weise auswirkt. Wie bereits erwähnt, ist der Typ der Variablen der Typ, mit dem Sie die Vorlage instanziiert haben. d.h. decltype(n<int>) ist int. decltype((double)n<int>) ist doppelt und so weiter.

Jedes Anwendungsbeispiel, um zu verstehen, wie man ein solches Feature optimal nutzt und wozu dient es?

N3651 bietet eine kurze Begründung.

Leider lassen vorhandene C++ - Regeln eine Vorlagedeklaration nicht zu deklarieren eine Variable. Es sind gut bekannt Abhilfen für dieses Problem:

• Verwendung constexpr statische Datenelemente der Klasse Vorlagen

• Verwendung constexpr Funktionsschablonen die gewünschten Werte Rückkehr

Diese Abhilfen für bekannt wurden Jahrzehnte und gut dokumentiert. Standardklassen wie std :: numeric_limits sind archetypische Beispiele. Obwohl diese Umgehungslösungen nicht perfekt sind, waren ihre Nachteile bis zu einem gewissen Grad tolerierbar, weil in der C++ 03 Ära nur einfache, eingebaute Typen Konstanten ungehindert direkten und effizienten kompilieren Zeitunterstützung genossen. All dies änderte sich mit der Einführung von constexpr-Variablen in C++ 11, die die direkte und effiziente -Unterstützung für Konstanten benutzerdefinierter Typen erweiterten. Jetzt sind Programmierer , die Konstanten (von Klassentypen) in Programmen mehr und mehr offensichtlich machen. So wachsen die Verwirrung und Frustrationen im Zusammenhang mit den Workarounds.

...

Die Hauptprobleme bei "statisches Datenelement" sind:

• sie "Duplikat" Erklärungen benötigen: einmal in der Klasse Vorlage, einmal außerhalb der Klassenvorlage, um die "echte" Definition zu liefern, falls die Konstanten odr-verwendet werden.

• Programmierer sind beide verärgert und verwirrt durch die Notwendigkeit, zweimal die gleiche Erklärung zu liefern. Im Gegensatz dazu benötigen "gewöhnliche" Konstanten-Deklarationen keine doppelten Deklarationen .

...

Bekannte Beispiele in dieser Kategorie sind wahrscheinlich statisches Element Funktionen von numeric_limits oder Funktionen wie boost::constants::pi<T>() usw. constexpr Funktionen Vorlagen nicht leiden die " doppelte Deklarationen "geben Sie an, dass statische Datenelemente haben; Darüber hinaus bieten sie funktionale Abstraktion. Sie zwingen jedoch den Programmierer, im Voraus an der Definitionsseite zu wählen, wie die Konstanten geliefert werden sollen: entweder durch eine Konstante const oder durch plain non reference type.Wenn die Konstante const übergeben wird, müssen die Konstanten systematisch im statischen Speicher zugewiesen werden. Wenn vom Nicht-Referenztyp, müssen die Konstanten kopiert werden. Kopieren ist nicht ein Problem für Builttin-Typen, aber es ist ein Showstopper für benutzerdefinierte Typen mit Wert Semantik, die nicht nur Wrapper um winzige Built-In-Typen (zB Matrix oder Integer oder Bigfloat, etc.) sind Kontrast, "gewöhnliche" const (expr) Variablen leiden nicht unter diesem Problem. Es wird eine einfache Definition zur Verfügung gestellt, und die Entscheidung , ob die Konstanten tatsächlich nur im Speicherlayout ausgegeben werden müssen, hängt von der Verwendung ab, nicht von der Definition.

5

Ich frage mich, ob etwas in dieser Richtung möglich wäre: (Verfügbarkeit der Vorlage lambdas vorausgesetzt) ​​

void some_func() { 
    template<typename T> 
    std::map<int, T> storage; 

    auto store = []<typename T>(int key, const T& value) { storage<T>[key] = value; }; 

    store(0, 2); 
    store(1, "Hello"s); 
    store(2, 0.7); 

    // All three values are stored in a different map, according to their type. 
} 

Nun, dies ist sinnvoll?

Als eine einfachere Verwendung, beachten Sie, dass die Initialisierung von pi<T> explizite Konvertierung (expliziter Aufruf eines unären Konstruktors) und nicht einheitliche Initialisierung verwendet. Das bedeutet, dass Sie bei einem Typ radians mit einem Konstruktor radians(double)pi<radians> schreiben können.

+1

Leider ist Ihr Code nicht gültig. Der Vorschlag macht keine Syntaxänderungen möglich. 'Der Grund ist, dass die aktuelle Grammatik jede Deklaration parametrisieren lässt. Probieren Sie es auf [coliru] (http://coliru.stacked-crooked.com/) mit 'clang ++ --std = C++ 1y' aus. –

+0

Ich habe BTW nicht downvote. –

+0

@remyabel: Ich verstehe es nicht. Ich habe zwei Funktionen verwendet: Template-Variablen und Template-Lambdas. Template-Lambdas werden noch nicht akzeptiert. –

18

können wir über diese Funktion nur durch eine Variable in einer Templat-Struktur oder Klasse Einwickeln

Ja, aber die unentgeltliche syntaktisches Salz wäre. Nicht gesund für den Blutdruck.

pi<double> vermittelt die Absicht besser als pi<double>::value. Kurz und auf den Punkt. Das ist ein Grund in meinem Buch, diese Syntax zu erlauben und zu fördern.

4

Ein weiteres praktisches Beispiel für C++ 14 Variablen Vorlagen ist, wenn man etwas in std::accumulate für das Bestehen einer Funktion benötigen:

template<typename T> 
T const & (*maxer) (T const &, T const &) = std::max<T>; 

std::accumulate(some.begin(), some.end(), initial, maxer<float>); 

Beachten Sie, dass std::max<T> mit unzureichend ist, weil es die genaue Signatur nicht ableiten kann . In diesem speziellen Beispiel können Sie stattdessen max_element verwenden, aber der Punkt ist, dass es eine ganze Klasse von Funktionen gibt, die dieses Verhalten teilen.

1

Nun können Sie diesmal Code wie diesen zu schreiben, verwenden zu kompilieren:

#include <iostream> 

template <int N> const int ctSquare = N*N; 

int main() { 
    std::cout << ctSquare<7> << std::endl; 
} 

Dies ist eine deutliche Verbesserung gegenüber dem äquivalenten

#include <iostream> 

template <int N> struct ctSquare { 
    static const int value = N*N; 
}; 

int main() { 
    std::cout << ctSquare<7>::value << std::endl; 
} 

, die Menschen zu schreiben verwendet, um Metaprogrammierung auszuführen, bevor Variable Vorlagen wurden eingeführt. Für Nicht-Typ-Werte konnten wir dies seit C++ 11 mit constexpr tun, so dass Template-Variablen nur den Vorteil haben, Berechnungen basierend auf Typen zu den variablen Templates zu erlauben.

TL; DR: Sie erlauben uns nicht, etwas zu tun, was wir vorher nicht tun konnten, aber sie machen eine Metaprogrammierung weniger PITA.

+0

Zwischen dieser Funktion und den Shorthands/Helfern wie 'std :: conditional_t' usw. frage ich mich oft, warum sie so spät kamen. Die "[Faustregeln] (https://accu.org/content/conf2013/Bjarnes_Talk.pdf)" machen prinzipiell Sinn, aber Dinge wie "Fügen Sie keine Features hinzu, nur um der Mode zu folgen" und "in der Lage zu sein etwas ist nicht Grund genug, es zu tun "klingt klar wie Erklärungen für die Flak C++ TMP-Syntax dauert. Wenn ich mehr über den TR/TS-Prozess wüsste, würde ich das verstehen. –

Verwandte Themen