Pergunta

Se eu tiver um recipiente (vector, list, etc) onde cada elemento é uma std::pair, há uma maneira fácil de iterar sobre cada elemento de cada par?

i.

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));

e, em seguida, ser capaz de interagir sobre o valor:? 1,3,2,3,4,2,5,2,1,5

Da mesma forma, o tipo de functor / função voltaria a me um recipiente (do mesmo tipo) com um apartamento lista dos elementos par como acima?

Foi útil?

Solução

Para aplainar seu recipiente de pares em um segundo recipiente que você também pode simplesmente escrever a sua própria inserção:

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));

Outras dicas

Para o seu primeiro, você tem que criar sua própria classe iterator, que pares de um sinalizador que indica a posição dentro de par com um container<pair> iterador

Para o segundo, é mais fácil, apesar de ser tão geral como você quer (recipiente de mesmo tipo) você precisa de um modelo typedef . Aqui é para apenas vector:

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;
}

Veja como você fingir um typedef template:

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);

O código a seguir irá imprimir todos os valores conforme necessário:

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

Eu prefiro esta maneira fácil de criar iterador personalizado.

Não há nenhuma maneira simples de realizar a iteração você quiser, mas você pode querer dar uma olhada na biblioteca boost :: iterator_adaptor ou implementar seu próprio iterador para fazê-lo (ele não deve ser muito complexo). Em seguida, na segunda pergunta, você pode usar std :: copy com o seu novo adaptador de iterador.

Não, não há realmente uma coisa dessas para std::pair. Você pode querer considerar o uso de um Tuple impulso em seu lugar. Uma tupla é um pouco como uma versão expandida do std::pair que permite que um número arbitrário de elementos (até certo limite, mas normalmente pelo menos 10), e dá acesso aos elementos algo como um vetor / array bem (ou seja, você pode acessar os elementos por nome ou índice).

TR1 também inclui std :: tr1 :: tuple, que é um subconjunto de tupla do Boost, mas se serve de memória, ele ainda inclui a funcionalidade nome / index que você está pedindo.

Edit: Note-se que em ambos os casos, a notação de índice requer um tempo de compilação constante para o índice, então você não pode escrever um (run-time) loop para iterar sobre os elementos em uma tupla - mas você pode fazer o trabalho com um pouco de metaprogramming. fusion impulso inclui um pouco para apoiar o que você precisa (por alguma estranha coincidência, tupla é parte da biblioteca de fusão).

Em algum momento você precisa usar início e segunda , mesmo se você criar sua própria classe iterator. Eu não acho que há um caminho para sair dela (pelo menos, de uma forma portátil).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top