4

如果我有一个容器(vector,list等),其中每个元素都是 a std::pair,是否有一种简单的方法可以迭代每对中的每个元素?

IE

std::vector<std::pair<int,int> > a;
a.push_back(std::pair(1,3));
a.push_back(std::pair(2,3));
a.push_back(std::pair(4,2));
a.push_back(std::pair(5,2));
a.push_back(std::pair(1,5));

然后能够迭代值:1,3,2,3,4,2,5,2,1,5?

类似地,什么类型的函子/函数会返回给我一个容器(相同类型),其中包含上述对元素的平面列表?

4

6 回答 6

7

首先,您必须创建自己的迭代器类,它将指示对内位置的标志与container<pair>迭代器配对

其次,它更容易,尽管要像你想要的那样通用(相同类型的容器),你需要一个模板 typedef。这里只是向量:

template <class V>
std::vector<V> flatten_pairs(std::vector<std::pair<V,V> > const& a) {
  typedef std::vector<std::pair<V,V> > A;
  std::vector<V> ret;
  for (typename A::const_iterator i=a.begin(),e=a.end();i!=e;++i) {
    ret.push_back(i->first);
    ret.push_back(i->second);
  }
  return ret;
}

下面是你如何伪造一个模板 typedef:

template <class C>
struct same_container;

template <class V>
struct same_container<std::vector<V> > {
  template <class W> struct rebind { typedef std::vector<W> type; };
};

template <class V>
struct same_list<std::list<V> > {
  template <class W> struct rebind { typedef std::list<W> type; };
};

template <class C>
typename same_container<C>::rebind<typename C::value_type::first_type>::type
flatten_pairs(C const& a);
于 2009-11-30T19:33:31.610 回答
5

以下代码将根据需要打印所有值:

for ( size_t x = 0; x < a.size(); ++x ) {
    cout << a[x].first << "," << a[x].second << ",";
}

与创建自定义迭代器相比,我更喜欢这种简单的方法。

于 2009-11-30T19:36:28.080 回答
3

要将您的对容器扁平化为第二个容器,您还可以简单地编写自己的插入器:

template<class C>
struct Inserter {
    std::back_insert_iterator<C> in;
    Inserter(C& c) : in(c) {}
    void operator()(const std::pair<typename C::value_type, typename C::value_type>& p)
    {
        *in++ = p.first;
    *in++ = p.second;
    }
};

template<class C>
Inserter<C> make_inserter(C& c)
{ 
    return Inserter<C>(c); 
}

// usage example:
std::list<int> l;
std::for_each(a.begin(), a.end(), make_inserter(l));
于 2009-11-30T19:55:46.773 回答
1

没有简单的方法来执行你想要的迭代,但你可能想看看 boost::iterator_adaptor 库或实现你自己的迭代器来完成它(它不应该太复杂)。然后,在第二个问题上,您可以将 std::copy 与新的迭代器适配器一起使用。

于 2009-11-30T19:35:58.700 回答
1

不,真的没有这样的事情std::pair。您可能要考虑改用 Boost Tuple。元组有点像它的扩展版本,std::pair它允许任意数量的元素(最多有一些限制,但通常至少 10 个),并且还可以访问向量/数组之类的元素(即您可以访问按名称或索引的元素)。

TR1 还包括 std::tr1::tuple,它是 Boost 元组的子集,但如果有记忆,它仍然包括您要求的名称/索引功能。

编辑:请注意,在这两种情况下,索引符号都需要索引的编译时常量,因此您不能编写(运行时)循环来迭代元组中的元素——但您可以完成这项工作有点元编程。Boost fusion 包含相当多的内容来支持您需要的东西(出于某种奇怪的巧合,元组是 fusion 库的一部分)。

于 2009-11-30T19:36:27.377 回答
0

在某些时候,您需要使用firstsecond,即使您创建了自己的迭代器类。我认为没有办法摆脱它(至少,以便携的方式)。

于 2009-11-30T19:33:15.087 回答