我已经看到了一些使用模板模板参数(即模板作为参数的模板)来进行基于策略的类设计的C++示例.这种技术有什么其他用途?
我正在尝试实现一个类似于std::transform算法的函数,而不是通过我想创建的参数获取输出迭代器,并返回一个带有转换输入元素的容器.
让我们说它的名称transform_container并带有两个参数:容器和仿函数.它应返回相同的容器类型,但可能由不同的元素类型进行参数化(Functor可以返回不同类型的元素).
我想使用我的函数,如下例所示:
std::vector<int> vi{ 1, 2, 3, 4, 5 };
auto vs = transform_container(vi, [] (int i) { return std::to_string(i); });
//vs will be std::vector<std::string>
assert(vs == std::vector<std::string>({"1", "2", "3", "4", "5"}));
std::set<int> si{ 5, 10, 15 };
auto sd = transform_container(si, [] (int i) { return i / 2.; });
//sd will be of type std::set<double>
assert(sd == std::set<double>({5/2., 10/2., 15/2.}));
Run Code Online (Sandbox Code Playgroud)
我能够写两个函数 - 一个for std::set和one for std::vector- 似乎正常工作.它们是相同的,除了容器类型名称.他们的代码如下所示.
template<typename T, typename Functor> …Run Code Online (Sandbox Code Playgroud) 而在寻找的std ::分配器,我看到的成员:
value_type,
pointer,
const_pointer,
reference,
const_reference,
size_type,
difference_type,和
rebind都被废弃了.
分配器也将不再有成员:
address, max_size, construct,或destroy.
为什么会这样?它与多态分配器有关吗?
试图更多地了解标准库是如何实现的我正在检查visual studio中的所有容器.在这里我看到一些奇怪的结构:
在a的某个基类中std::list<>找到以下typedef
typedef typename _Alloc::template rebind<_Ty>::other _Alty;
Run Code Online (Sandbox Code Playgroud)
其中"_Alloc"对应于allocator模板参数(和_Ty包含的类型).我很难找到这个"关键字"的好解释.到目前为止,我发现最好的是它是分配器接口的一部分.虽然甚至cppreference在解释这个问题上也不是很好.
这是template rebind<>做什么的?为什么在那个地方有必要?
STL 中所有分配器感知类模板都必须使用分配器类型进行实例化。如果分配器不是模板参数而是模板 模板参数,对用户来说不是更方便吗?
为了演示,std::vector 和 std::basic_string 类模板分别具有以下签名:
template<class T, class Allocator = std::allocator<T>> class vector;
template<class CharT, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT>> class basic_string;
Run Code Online (Sandbox Code Playgroud)
如果我有一个自定义分配器:
template <typename T>
class MyAllocator
{
// ...
};
Run Code Online (Sandbox Code Playgroud)
并且想要实例化一个字符串向量,该向量使用我的自定义分配器为向量和字符串的内部字符数组分配内部存储,事情很快就会变得尴尬:
typedef std::vector<std::basic_string<char, std::char_traits<char>, MyAllocator<char> >, MyAllocator<std::basic_string<char, std::char_traits<char>, MyAllocator<char>>>> CustomAllocStringVector;
Run Code Online (Sandbox Code Playgroud)
使用附加的 typedef,可以稍微简化:
typedef std::basic_string<char, std::char_traits<char>, MyAllocator<char>> CustomAllocString;
typedef std::vector<CustomAllocString, MyAllocator<CustomAllocString>> CustomAllocStringVector;
Run Code Online (Sandbox Code Playgroud)
但困扰我的是,为什么强制用户显式指定分配器的完整类型?如果我将分配器用于char向量,那么不应该说分配器的类型为 allocator< char > 吗?
如果 std::vector 和 std::basic_string 的签名是:
template<typename T, template <typename ElementType> class …Run Code Online (Sandbox Code Playgroud) 似乎C++ STL容器要求提供的分配器类型的value_type与STL容器的value_type相同
要求:allocator_- type :: value_type与X :: value_type相同.
但是,以下使用字符串向量但带有双精度分配器的代码在VS 2012和g ++ 4.4.7上运行正常.在g ++上,valgrind也不会产生任何错误.
int main()
{
typedef vector<std::string, std::allocator<double> > StringList;
StringList s;
for(int i=0; i < 100; i++){
stringstream ss;
ss << i;
s.push_back(ss.str());
}
for(StringList::iterator it = s.begin(); it != s.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我假设分配器正在内部反弹到容器的value_type的分配器(虽然可能我错了).
我的问题是我误读了C++规范,实际上所有容器都会"重新绑定"提供的分配器以使用他们想要的类型吗?或者这只是一种常见的做法,但不能保证.
基本上我可以依靠这个"功能",容器将始终采用我提供的任何分配器(任何类型)并使其适用于该容器的value_type?