Kurz gesagt: Weil die Verwendung eines Template-Vorlagenparameters restriktiver ist als die Verwendung eines Typparameters, ohne irgendwelche Vorteile zu bieten.
* Mit "restriktiv" meine ich, dass Sie möglicherweise ein komplexeres Zeug brauchen, um die gleichen Ergebnisse zu erhalten, die mit einem "einfachen" Typ-Parameter.
Warum gibt es keine Vorteile?
Ihre std::stack
wahrscheinlich ein Attribut wie dies:
template <typename T, typename Container>
struct stack {
Container container;
};
Wenn Sie Container
, durch einen Parameter Vorlage Vorlage ersetzen, warum sollten Sie erhalten?
template <typename T, template <typename...> class Container>
struct stack {
Container<T> container;
};
Du Instanziieren Container
nur einmal und nur für T
(Container<T>
), so gibt es keinen Vorteil für einen Template-Template-Parameter.
Warum ist es restriktiver?
Mit einem Template-Template-Parameter, müssen Sie eine Vorlage std::stack
geben, die die gleiche Signatur aussetzen, zB:
template <typename T, template <typename> class Container>
struct stack;
stack<int, std::vector> // Error: std::vector takes two template arguments
Vielleicht könnten Sie variadische Vorlagen verwenden:
template <typename T, template <typename....> class Container>
struct stack {
Container<T> container;
};
stack<int, std::vector> // Ok, will use std::vector<int, std::allocator<int>>
Aber was wenn ich nicht den Standard std::allocator<int>
verwenden möchte?
template <typename T,
template <typename....> class Container = std::vector,
typename Allocator = std::allocator<T>>
struct stack {
Container<T, Allocator> container;
};
stack<int, std::vector, MyAllocator> // Ok...
Dies ist ein bisschen chaotisch geworden ... Was passiert, wenn ich möchte, dass meine eigenen Container-Vorlagen verwenden, die 3/4/N Parameter nimmt?
template <typename T,
template <typename... > class Container = std::vector,
typename ...Args>
struct stack {
Container<T, Args...> container;
};
stack<int, MyTemplate, MyParam1, MyParam2> // Ok...
Aber was, wenn ich einen nicht-Vorlagenbehälter verwenden möchte?
struct foo { };
struct foo_container{ };
stack<foo, foo_container> // Error!
template <typename... >
using foo_container_template = foo_container;
stack<foo, foo_container_template> // Ok...
Mit einem Typ-Parameter gibt es keine solchen Probleme :
stack<int>
stack<int, std::vector<int, MyAllocator<int>>
stack<int, MyTemplate<int, MyParam1, MyParam2>>
stack<foo, foo_container>
Es gibt andere Fälle, die als mit Hilfe von Vorlagen zu akzeptieren eine Mischung nicht so mit Template-Template-Parameter arbeiten von type und non-type Parameter in bestimmten Aufträgen, für die Sie generische Vorlagenparameter auch mit variadischen Vorlagen erstellen können.
@CoryKramer diese Frage ist kein Duplikat der verknüpften Frage: Die verknüpfte Frage fragt, wo wir Template/Typname setzen müssen, während diese Frage darum geht, warum eine existierende Klasse ('deque') eine bestimmte Schnittstelle hat, nicht über eine syntaktische Frage. – bennofs
Funktionieren die Standardeinstellungen auch für Vorlagenvorlagenparameter? – anatolyg
@anatolyg Ja, sie funktionieren. –