为什么std::stack不使用template-template参数
Why does std::stack not use template template parameter?
为什么std::stack
和std::queue
的底层容器类型使用类型模板参数而不是模板模板参数?
即为什么stack
是这样声明的:
template<typename T, typename Container = deque<T>>
class stack;
但不是这样的:
template<typename T, template<typename> class Container = deque>
class stack;
因为像std::vector
这样的容器通常有多个模板参数。通过不关心它是一个模板,您可以使用各种容器。
将如何
template<class T, class Allocator = std::allocator<T>> class vector;
适合
template<typename> class Container
就像你在stack
中一样?(提示:没有!)你需要为你想要支持的每种数量和类型的模板参数(类型与非类型)设置特殊情况,这很愚蠢,因为这些参数通常不会比简单的提供更多的信息
typename Container
请注意,为了获得std::vector
等的实际模板参数,您有类型定义std::vector::value_type
和std::vector::allocator_type
,从而消除了在实际使用类型(即stack
的Container
)时显式使用这些类型的需要。
简而言之:因为使用模板模板参数比使用类型参数更具限制性*,而没有任何优势。
*限制性我的意思是,与使用"简单"类型参数相比,您可能需要更复杂的东西来获得相同的结果
为什么没有优势
您的std::stack
可能具有这样的属性:
template <typename T, typename Container>
struct stack {
Container container;
};
如果用模板模板参数替换Container
,为什么要获得?
template <typename T, template <typename...> class Container>
struct stack {
Container<T> container;
};
您只实例化了Container
一次,并且仅针对T
(Container<T>
),因此模板模板参数没有任何优点。
为什么限制性更强
使用template-template参数,您必须向std::stack
传递一个暴露相同签名的模板,例如:
template <typename T, template <typename> class Container>
struct stack;
stack<int, std::vector> // Error: std::vector takes two template arguments
也许你可以使用可变模板:
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>>
但是如果我不想使用标准的std::allocator<int>
呢?
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...
这变得有点乱。。。如果我想使用我自己的容器模板,它采用3/4/N参数,该怎么办?
template <typename T,
template <typename... > class Container = std::vector,
typename... Args>
struct stack {
Container<T, Args...> container;
};
stack<int, MyTemplate, MyParam1, MyParam2> // Ok...
但是,如果我想使用非模板化的容器呢?
struct foo { };
struct foo_container{ };
stack<foo, foo_container> // Error!
template <typename... >
using foo_container_template = foo_container;
stack<foo, foo_container_template> // Ok...
对于类型参数,不存在这样的问题1:
stack<int>
stack<int, std::vector<int, MyAllocator<int>>
stack<int, MyTemplate<int, MyParam1, MyParam2>>
stack<foo, foo_container>
1还有其他情况不适用于模板模板参数,例如使用按特定顺序接受类型和非类型参数组合的模板,您可以为其创建通用模板模板参数(即使使用可变模板)
使用模板模板参数会将可用作底层容器的类型限制为那些公开相同模板签名的类型。这种形式允许任意类型,只要它们支持预期的接口。
因为它不编译:
std::deque
不是类型
template <typename T> class std::deque
它是型
template<class T, class Alloc> class std::deque
当然,这是一个更普遍的问题:即使我们将Alloc
模板参数提供给stack
类模板,该类现在也只能使用正好有两个类型模板参数的容器。这是一个不合理的限制。
- 表示"accepting anything for this template argument" C++概念的通配符
- 传递给std::function template的template参数究竟代表什么
- 在template中使用std::variant的template函数
- C++ template for QList
- C++ - 为什么这里需要'template'关键字?
- 使用"std::enable_if_t" "function template has already been defined"
- C++模板错误:"invalid explicitly-specified argument for template parameter"
- C++ class template
- 在"template"和函数声明之间使用:template<typename trait> using tr = base_trait<trait> void fn(tr::t
- 为什么编译器说"candidate template ignored: couldn't infer template argument 'InputIterator'"?
- 为什么在这种情况下我需要 .template
- std::span constructor, libcxx vs libstdc++, template vs non-
- 模板函数参数到模板函数的"candidate template ignored: could not match ..."
- MacOS 上的 LLVM - 标准文件 iosfwd 中未知类型名称'template'
- std::get like (partial) template specialization
- 实现多类型算术运算符时如何解决"template argument deduction/substitution failure"
- 更新 Visual Studio 2017,现在出现编译错误 C7510:"回调":使用依赖模板名称必须以 'template' 为前缀
- C++ 中的"template <typename From, typename Tag> struct Alias;"是什么?
- Template类定义中的Template方法与声明不匹配
- 为什么在template函数广播中把两个extensor表达式加在一起不正确