C++ 更改给定STL容器的值类型

C++ 更改给定STL容器的值类型,c++,templates,stl,metaprogramming,containers,C++,Templates,Stl,Metaprogramming,Containers,假设我有一个STL容器类型(不是对象),比如说vector。现在它是value\u type是A,所以我想把它改成B 基本上,我需要此表单的类模板,或其变体: template<typename container, typename new_value_type> struct change_value_type { typedef /*....*/ new_container; }; 模板 结构更改\u值\u类型 { typedef/*....*/新容器; }; 因

假设我有一个STL容器类型(不是对象),比如说
vector
。现在它是
value\u type
A
,所以我想把它改成
B

基本上,我需要此表单的类模板,或其变体:

template<typename container, typename new_value_type>
struct change_value_type
{
    typedef /*....*/  new_container;
};
模板
结构更改\u值\u类型
{
typedef/*....*/新容器;
};
因此,我可以按以下方式使用它:

typename change_value_type<vector<A>, B>::new_container  vectorOfB; 
vectorOfB.push_back(B());
vectorOfB.push_back(B());
vectorOfB.push_back(B());
//etc
typename-change\u-value\u-type::new\u-container-vectorOfB;
向量B.推回(B());
向量B.推回(B());
向量B.推回(B());
//等
意味着,
新容器
向量


可能吗?

您(我相信)所指的是,使用rebind

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

#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);
}
#包括
#包括
#包括
#包括
模板
结构重新绑定\u序列\u容器;
模板
结构重新绑定\u序列\u容器
{
类型定义容器类型;
};
模板
无效试验(常数新类型&n)
{
typename重新绑定序列容器::类型c;
c、 推回(n);
}
int main()
{
std::字符串s;
测试;
测试;
测试;
}
但是,容器可能没有这两个模板参数


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

我只是在尝试从本质上解决相同的问题时偶然发现了这个问题。它甚至可以在不依赖特定于
std::allocator
rebind
类型的情况下工作–唯一的要求是回弹值类型是各个类的第一个模板参数。所有相关STL类(
std::vector
std::set
std::list
等)以及例如
std::less
std::allocator
)都是这种情况

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

template <class Container, class NewType>
struct rebind;

template <class ValueType, template <class> class Container, class NewType>
struct rebind<Container<ValueType>, NewType>
{
  typedef Container<NewType> type;
};

template <class ValueType, class A, template <class, class> class Container, class NewType>
struct rebind<Container<ValueType, A>, NewType>
{
  typedef Container<NewType, typename rebind<A, ValueType>::type> type;
};

template <class ValueType, class A, class B, template <class, class, class> class Container, class NewType>
struct rebind<Container<ValueType, A, B>, NewType>
{
  typedef Container<NewType, typename rebind<A, ValueType>::type, typename rebind<B, ValueType>::type> type;
};

// Continue for more parameters (A, B, C, ...)
结果可用于几乎任何STL类型:

#include <iostream>
#include <typeinfo>
#include <vector>
#include <set>
#include <deque>
#include <queue>
#include <list>
#include <array>

#include "rebind.h"

// Make it all a bit more compact
#define REBIND_DEMO(container, new_type)                \
  do {                                                  \
    container test;                                     \
    rebind<decltype(test), new_type>::type test2;       \
    std::cout << typeid(test).name() << "\n";           \
    std::cout << typeid(test2).name() << "\n";          \
  } while (0)

int main()
{
  REBIND_DEMO(std::set<float>, double);
  REBIND_DEMO(std::list<float>, double);
  REBIND_DEMO(std::deque<float>, double);
  REBIND_DEMO(std::queue<float>, double);
  typedef std::array<float, 4> TestArray;
  REBIND_DEMO(TestArray, double);
  REBIND_DEMO(std::unordered_set<float>, double);

  return 0;
}

如果它的格式是
set\u value\u type
。我可以用那个表格。当我将
向量
类型
一起使用时,问题就来了,比如
向量
。我已经提到了这一点:@gnobal:No。这不是我指的。这个成语的形式是:
change\u value\u type
,而不是
change\u value\u type
。@Nawaz:你读得不够仔细,这个成语的形式是
vector::rebind
,不需要类模板(
vector
)。@Ben:这意味着,托马斯说没有通用解决方案是错的?@Nawaz,据我所知,这个习惯用法要求类为“responder”,需要有一个特定的typedef来实现“responder”。由于std::vector和其他STL容器似乎没有类似的内容,因此不能对它们使用此习惯用法。所以它不是一个通用的解决方案,因为它只适用于您控制的类。@UncleBens,我已经尝试过了,它抱怨std::vector类中没有
重新绑定
。我也看过
标题,但似乎没有这样的内容。显然STL只对分配器使用这个习惯用法,而不是容器本身。你自己试过了吗?我试过了,但没用。请试着确认一下,我很惊讶。我试了将近一个小时,但没有成功;不行。但现在你的解决方案奏效了。怎么会?特殊形式中类型参数的顺序重要吗?@Nawaz:不知道出了什么问题。如果它能工作的话,它将只对序列容器工作。(重新绑定谓词会变得非常疯狂…)序列容器?这是怎么一回事?STL中还有哪些其他容器?@Nawaz:它们是vector、list和deque。队列、优先级队列和堆栈是容器适配器(底层容器上的特定接口)。集合、多重集合、贴图和多重贴图是关联容器。
template <class ValueType, std::size_t N, template <class, std::size_t> class Container, class NewType>
struct rebind<Container<ValueType, N>, NewType>
{
  typedef Container<NewType, N> type;
};
#include <iostream>
#include <typeinfo>
#include <vector>
#include <set>
#include <deque>
#include <queue>
#include <list>
#include <array>

#include "rebind.h"

// Make it all a bit more compact
#define REBIND_DEMO(container, new_type)                \
  do {                                                  \
    container test;                                     \
    rebind<decltype(test), new_type>::type test2;       \
    std::cout << typeid(test).name() << "\n";           \
    std::cout << typeid(test2).name() << "\n";          \
  } while (0)

int main()
{
  REBIND_DEMO(std::set<float>, double);
  REBIND_DEMO(std::list<float>, double);
  REBIND_DEMO(std::deque<float>, double);
  REBIND_DEMO(std::queue<float>, double);
  typedef std::array<float, 4> TestArray;
  REBIND_DEMO(TestArray, double);
  REBIND_DEMO(std::unordered_set<float>, double);

  return 0;
}
std::set<float, std::less<float>, std::allocator<float> >
std::set<double, std::less<double>, std::allocator<double> >
std::list<float, std::allocator<float> >
std::list<double, std::allocator<double> >
std::deque<float, std::allocator<float> >
std::deque<double, std::allocator<double> >
std::queue<float, std::deque<float, std::allocator<float> > >
std::queue<double, std::deque<double, std::allocator<double> > >
std::array<float, 4ul>
std::array<double, 4ul>
std::unordered_set<float, std::hash<float>, std::equal_to<float>, std::allocator<float> >
std::unordered_set<double, std::hash<double>, std::equal_to<double>, std::allocator<double> >