C++ C++;

C++ C++;,c++,templates,higher-kinded-types,C++,Templates,Higher Kinded Types,我正在尝试编写一个函数,它接受两个包含类型相同的容器,例如,两个std::vectors,或者一个std::list和一个std::vector。(但不是std::vector和std::vector!) 由于我不太确定应该如何做,我决定先编写一个测试程序: #include <iostream> #include <vector> #include <list> #include <algorithm> struct vector_wrappe

我正在尝试编写一个函数,它接受两个包含类型相同的容器,例如,两个
std::vector
s,或者一个
std::list
和一个
std::vector
。(但不是
std::vector
std::vector
!)

由于我不太确定应该如何做,我决定先编写一个测试程序:

#include <iostream>
#include <vector>
#include <list>
#include <algorithm>

struct vector_wrapper
{
  template <typename T>
  struct instance_wrapper
  {
    typedef typename std::vector<T> instance;
  };
};

struct list_wrapper
{
  template <typename T>
  struct instance_wrapper
  {
    typedef typename std::list<T> instance;
  };
};

template <typename T, typename C1, typename C2>
void move(typename C1::instance_wrapper<T>::instance& c1, typename C2::instance_wrapper<T>::instance& c2) // line 29
{
  while (c1.size() > 0)
  {
    c2.push_front(c1.back());
    c1.pop_back();
  }
}

int main()
{
  std::vector<int> v;
  std::list  <int> l;

  v.reserve(10);
  for (int i = 0; i < 10; ++i)
    v.push_back(i);

  move<int, vector_wrapper, list_wrapper>(v, l);

  std::for_each(l.begin(), l.end(),
    [] (int i) { std::cout << i << " "; }
  );

  std::cout << std::endl;

  return 0;
}

为什么编译器没有正确地将
实例\u包装器
标识为模板?

编译器已经告诉您错误(错误来自:

程序cpp:25:24:错误:非模板“实例包装器”用作模板
prog.cpp:25:24:注意:使用“C1::template instance_wrapper”表示它是一个模板

使用
C1::template instance_wrapper
而不是
C1::instance_wrapper
——同样,对
C2::instance_wrapper
也要这样做:

template <typename T, typename C1, typename C2>
void move(typename C1::template instance_wrapper<T>::instance& c1, 
    typename C2::template instance_wrapper<T>::instance& c2)
{
    // ...
模板
无效移动(类型名称C1::模板实例\包装器::实例和C1,
typename C2::模板实例(包装器::实例和C2)
{
// ...
这是因为
C1
是模板,编译器无法推断
instance\u wrapper
是模板,并将其视为非模板类型


请,请阅读编译器输出的所有内容。不仅仅是一行一行。通常,编译器会在前面或后面的一行中指出问题所在,就像在这种情况下,当它已经给出答案时!

这里有一个更好的解决方案,它不需要任何奇怪的包装器来禁用参数推断并让客户端spe请告诉他们,在C++03中工作的简单明了的SFINAE:

#include <type_traits> // or Boost equivalent

// a little helper struct to keep the 
// function as clutter-free as possible
template<class C1, class C2, class T = void>
struct enable_if_same_value_type
  : std::enable_if<std::is_same<typename C1::value_type,
        typename C2::value_type>::value, T>
{
};

template<class C1, class C2>
typename enable_if_same_value_type<C1, C2>::type
move(C1& source, C2& target){
  /* ... */
}

为了便于将来参考,您可以更简单地执行以下操作:

#include <type_traits>

template<typename T, typename A1, typename A2, template <typename, typename> class Cont1, template<typename, typename> class Cont2>
void move(Cont1<T, A1>& from, Cont2<T, A2>& to) {
    while (!from.empty()) { // use !empty(), not size()
        to.push_front(from.back());
        from.pop_back();
    }
}

std::vector<int> v;
std::list<int> l;

move(v, l); // and no need to specify types
#包括
模板
无效移动(Cont1和from,Cont2和to){
而(!from.empty()){//使用!empty(),而不是size()
向前推(从向后推());
from.pop_back();
}
}
std::向量v;
std::列表l;
move(v,l);//并且不需要指定类型

< /代码>我从来都不知道必须插入<代码>模板>代码>。我想你每天都会学到一些东西!):<代码> STD::队列,<代码> STD::Stase和<代码> STD::(unOrdEdId)(多){map,SET}
想和你谈谈:P@Xeomeh,没人关心它们。以及所有用户定义的容器,它们不只是有两个模板参数*查看Boost*@Xeo是的,出于这个原因(以及其他原因),您的方式更好。我在接受第一个答案15分钟后发现了这一点。事实上,为了让这项工作顺利进行,这需要两个typedef模板:。此外,这个答案需要更多的升级投票。您不需要额外的结构,您可以执行
typename std::enable_if::type move(…){…}
@Seth:struct只是为了看起来更干净。不过,将SFINAE移到了返回类型。关于
enable\u if
:这种古怪正是推动我的原因(老实说,它继续推动我)另外,我的
move
函数并不意味着是一个
std::move
重载,我只是以一种不明智的方式选择了函数名。@Eduardo:我只是在谈论命名,与
std::move
没有任何关系。我说的是
std::move
重载,因为迭代器是int
,以及
中的移动语义。
#include <algorithm> // algorithmic move
#include <vector>
#include <list>
#include <iterator> // front_inserter
#include <iostream>

int main(){
  std::vector<int> v;
  std::list<int> l;

  v.reserve(10);
  for (unsigned i = 0; i < 10; ++i)
    v.push_back(i);

  // I used 'rbegin'  and 'rend' so the order stays the same
  std::move(v.rbegin(), v.rend(), std::front_inserter(l));

  std::copy(l.begin(), l.end(), std::ostream_iterator<int>(std::cout, " "));
}
#include <type_traits>

template<typename T, typename A1, typename A2, template <typename, typename> class Cont1, template<typename, typename> class Cont2>
void move(Cont1<T, A1>& from, Cont2<T, A2>& to) {
    while (!from.empty()) { // use !empty(), not size()
        to.push_front(from.back());
        from.pop_back();
    }
}

std::vector<int> v;
std::list<int> l;

move(v, l); // and no need to specify types