更改给定 STL 容器的 value_type

Naw*_*waz 5 c++ containers templates stl metaprogramming

假设我有一个 STL 容器类型(不是对象),例如vector<A>. 现在是这样value_typeA所以我想把它改成B

基本上,我想要一个这种形式的类模板,或其变体:

template<typename container, typename new_value_type>
struct change_value_type
{
    typedef /*....*/  new_container;
};
Run Code Online (Sandbox Code Playgroud)

这样我就可以按以下方式使用它:

typename change_value_type<vector<A>, B>::new_container  vectorOfB; 
vectorOfB.push_back(B());
vectorOfB.push_back(B());
vectorOfB.push_back(B());
//etc
Run Code Online (Sandbox Code Playgroud)

意思是,new_containervector<B>

是否可以?

min*_*iot 6

当我试图从本质上解决同样的问题时,偶然发现了这一点。它甚至可以在不依赖rebind于 \xe2\x80\x93 特定类型的情况下工作std::allocator,唯一的要求是反弹值类型是各个类的第一个模板参数。std::vector所有相关的 STL 类( 、std::setstd::list以及例如std::lessstd::allocator)都是这种情况。

\n\n

C++11 之前的解决方案如下所示:

\n\n
template <class Container, class NewType>\nstruct rebind;\n\ntemplate <class ValueType, template <class> class Container, class NewType>\nstruct rebind<Container<ValueType>, NewType>\n{\n  typedef Container<NewType> type;\n};\n\ntemplate <class ValueType, class A, template <class, class> class Container, class NewType>\nstruct rebind<Container<ValueType, A>, NewType>\n{\n  typedef Container<NewType, typename rebind<A, ValueType>::type> type;\n};\n\ntemplate <class ValueType, class A, class B, template <class, class, class> class Container, class NewType>\nstruct rebind<Container<ValueType, A, B>, NewType>\n{\n  typedef Container<NewType, typename rebind<A, ValueType>::type, typename rebind<B, ValueType>::type> type;\n};\n\n// Continue for more parameters (A, B, C, ...)\n
Run Code Online (Sandbox Code Playgroud)\n\n

C++11 让它变得更容易一些:

\n\n
template <class Container, class NewType>\nstruct rebind;\n\ntemplate <class ValueType, class... Args, template <class...> class Container, class NewType>\nstruct rebind<Container<ValueType, Args...>, NewType>\n{\n  typedef Container<NewType, typename rebind<Args, NewType>::type...> type;\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

为了支持std::array,可以添加以下内容:

\n\n
template <class ValueType, std::size_t N, template <class, std::size_t> class Container, class NewType>\nstruct rebind<Container<ValueType, N>, NewType>\n{\n  typedef Container<NewType, N> type;\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果几乎可以与任何 STL 类型一起使用:

\n\n
#include <iostream>\n#include <typeinfo>\n#include <vector>\n#include <set>\n#include <deque>\n#include <queue>\n#include <list>\n#include <array>\n\n#include "rebind.h"\n\n// Make it all a bit more compact\n#define REBIND_DEMO(container, new_type)                \\\n  do {                                                  \\\n    container test;                                     \\\n    rebind<decltype(test), new_type>::type test2;       \\\n    std::cout << typeid(test).name() << "\\n";           \\\n    std::cout << typeid(test2).name() << "\\n";          \\\n  } while (0)\n\nint main()\n{\n  REBIND_DEMO(std::set<float>, double);\n  REBIND_DEMO(std::list<float>, double);\n  REBIND_DEMO(std::deque<float>, double);\n  REBIND_DEMO(std::queue<float>, double);\n  typedef std::array<float, 4> TestArray;\n  REBIND_DEMO(TestArray, double);\n  REBIND_DEMO(std::unordered_set<float>, double);\n\n  return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

c++filt -t在 Linux 系统上运行它并通过管道输出可以得到

\n\n
std::set<float, std::less<float>, std::allocator<float> >\nstd::set<double, std::less<double>, std::allocator<double> >\nstd::list<float, std::allocator<float> >\nstd::list<double, std::allocator<double> >\nstd::deque<float, std::allocator<float> >\nstd::deque<double, std::allocator<double> >\nstd::queue<float, std::deque<float, std::allocator<float> > >\nstd::queue<double, std::deque<double, std::allocator<double> > >\nstd::array<float, 4ul>\nstd::array<double, 4ul>\nstd::unordered_set<float, std::hash<float>, std::equal_to<float>, std::allocator<float> >\nstd::unordered_set<double, std::hash<double>, std::equal_to<double>, std::allocator<double> >\n
Run Code Online (Sandbox Code Playgroud)\n


Unc*_*ens 3

您可以尝试专门使用模板模板参数。

#include <vector>
#include <list>
#include <deque>
#include <string>

template <class T, class NewType>
struct rebind_sequence_container;

template <class ValueT, class Alloc, template <class, class> class Container, class NewType>
struct rebind_sequence_container<Container<ValueT, Alloc>, NewType >
{
     typedef Container<NewType, typename Alloc::template rebind<NewType>::other > type;
};

template <class Container, class NewType>
void test(const NewType& n)
{
    typename rebind_sequence_container<Container, NewType>::type c;
    c.push_back(n);
}

int main()
{
    std::string s;
    test<std::vector<int> >(s);
    test<std::list<int> >(s);
    test<std::deque<int> >(s);
}
Run Code Online (Sandbox Code Playgroud)

但是,容器可能没有这两个模板参数。

此外,在容器适配器和关联容器中,不仅仅是分配器需要替换(适配器中的底层容器, 中的谓词std::set)。OTOH,它们的用法与序列容器如此不同,以至于很难想象一个适用于任何容器类型的模板。