C ++ 11 oferece várias maneiras de iterar em contêineres. Por exemplo:
Loop baseado em alcance
for(auto c : container) fun(c)
std :: for_each
for_each(container.begin(),container.end(),fun)
No entanto, qual é a maneira recomendada de iterar em dois (ou mais) contêineres do mesmo tamanho para realizar algo como:
for(unsigned i = 0; i < containerA.size(); ++i) {
containerA[i] = containerB[i];
}
c++
c++11
iterator
containers
memecs
fonte
fonte
transform
apresentar em#include <algorithm>
?containerA = containerB;
invés do loop.Respostas:
Um pouco tarde para a festa. Mas: eu iria iterar sobre os índices. Mas não com o
for
loop clássico, mas sim com umfor
loop baseado em intervalo sobre os índices:indices
é uma função de invólucro simples que retorna um intervalo (avaliado lentamente) para os índices. Como a implementação - embora simples - é um pouco longa para postá-la aqui, você pode encontrar uma implementação no GitHub .Este código é tão eficiente quanto usar um
for
loop clássico manual .Se esse padrão ocorrer com frequência em seus dados, considere usar outro padrão que seja
zip
duas sequências e produza uma gama de tuplas, correspondendo aos elementos emparelhados:A implementação de
zip
é deixada como um exercício para o leitor, mas decorre facilmente da implementação deindices
.(Antes do C ++ 17, você teria que escrever o seguinte :)
fonte
boost::counting_range(size_t(0), containerA.size())
indices
implementação produz uma saída do compilador que é idêntica ao uso defor
loops manuais . Não há sobrecarga alguma.Para seu exemplo específico, basta usar
Para o caso mais geral, você pode usar Boost.Iterator's
zip_iterator
, com uma pequena função para torná-lo utilizável em loops for baseados em intervalo. Na maioria dos casos, isso funcionará:Exemplo ao vivo.
No entanto, para genericidade full-blown, você provavelmente vai querer algo mais parecido com este , que irá funcionar correctamente para arrays e tipos definidos pelo usuário que não têm membro
begin()
/end()
mas não têmbegin
/end
funções em seu namespace. Além disso, isso permitirá que o usuário obtenhaconst
acesso especificamente por meio daszip_c...
funções.E se você é um defensor de boas mensagens de erro, como eu, então provavelmente você quer isso , que verifica se algum contêiner temporário foi passado para alguma das
zip_...
funções e imprime uma boa mensagem de erro em caso afirmativo.fonte
auto
funciona exatamente da mesma forma que um parâmetro de modelo e,T&&
em um modelo, é uma referência universal, conforme explicado no primeiro link, portanto,auto&& v = 42
será deduzido comoint&&
eauto&& w = v;
, em seguida, será deduzido comoint&
. Ele permite que você combine lvalues, bem como rvalues, e permite que ambos sejam mutáveis, sem fazer uma cópia.zip_range
.Eu me pergunto por que ninguém mencionou isso:
PS: se os tamanhos do contêiner não corresponderem, você terá que colocar o código dentro das instruções if.
fonte
Existem várias maneiras de fazer coisas específicas com vários contêineres, conforme fornecido no
algorithm
cabeçalho. Por exemplo, no exemplo que você deu, você poderia usar emstd::copy
vez de um loop for explícito.Por outro lado, não há nenhuma maneira integrada de iterar genericamente vários contêineres além de um loop for normal. Isso não é surpreendente porque existem várias maneiras de iterar. Pense nisso: você poderia iterar por meio de um contêiner com uma etapa, um contêiner com outra etapa; ou através de um contêiner até chegar ao fim, então comece a inserir enquanto vai até o final do outro contêiner; ou uma etapa do primeiro contêiner para cada vez que você passar completamente pelo outro contêiner e depois reiniciar; ou algum outro padrão; ou mais de dois contêineres por vez; etc ...
No entanto, se você quiser fazer sua própria função de estilo "for_each" que itera por meio de dois contêineres apenas até o comprimento do mais curto, poderá fazer algo assim:
Obviamente, você pode fazer qualquer tipo de estratégia de iterações que desejar de maneira semelhante.
Claro, você pode argumentar que apenas fazer o loop for interno diretamente é mais fácil do que escrever uma função customizada como esta ... e você está certo, se for fazer isso apenas uma ou duas vezes. Mas o bom é que isso é muito reutilizável. =)
fonte
for (Container1::iterator i1 = c1.begin(), Container2::iterator i2 = c2.begin(); (i1 != end1) && (i2 != end2); ++it1, ++i2)
mas o compilador grita. Alguém pode explicar por que isso é inválido?for (int x = 0, y = 0; ...
funciona, masfor (int x = 0, double y = 0; ...)
não funciona.typename...
No caso de você precisar iterar simultaneamente em apenas 2 contêineres, há uma versão estendida do algoritmo for_each padrão na biblioteca de intervalo de impulso, por exemplo:
Quando você precisa lidar com mais de 2 contêineres em um algoritmo, precisa brincar com o zip.
fonte
outra solução poderia ser capturar uma referência do iterador do outro contêiner em um lambda e usar o operador de pós-incremento nisso. por exemplo, uma cópia simples seria:
dentro do lambda, você pode fazer qualquer coisa
ita
e incrementá-lo. Isso se estende facilmente ao caso de vários contêineres.fonte
Uma biblioteca de alcance fornece esta e outras funcionalidades muito úteis. O exemplo a seguir usa Boost.Range . O rangev3 de Eric Niebler deve ser uma boa alternativa.
C ++ 17 tornará isso ainda melhor com ligações estruturadas:
fonte
delme.cxx:15:25: error: no match for 'operator=' (operand types are 'std::tuple<int&, char&>' and 'const boost::tuples::cons<const int&, boost::tuples::cons<const char&, boost::tuples::null_type> >') std::tie(ti,tc) = i;
^19.13.26132.0
e Windows SDK10.0.16299.0
):error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const boost::tuples::cons<const char &,boost::fusion::detail::build_tuple_cons<boost::fusion::single_view_iterator<Sequence,boost::mpl::int_<1>>,Last,true>::type>' (or there is no acceptable conversion)
boost::combine
: stackoverflow.com/q/55585723/8414561Também estou um pouco atrasado; mas você pode usar isto (função variadic de estilo C):
ou isto (usando um pacote de parâmetros de função):
ou isto (usando uma lista de inicializadores entre chaves):
ou você pode juntar vetores como aqui: Qual é a melhor maneira de concatenar dois vetores? e, em seguida, itere sobre um grande vetor.
fonte
Aqui está uma variante
Exemplo de uso
fonte