Existe um adaptador de contêiner que inverta a direção dos iteradores para que eu possa iterar sobre um contêiner invertido com loop for baseado em intervalo?
Com iteradores explícitos, eu converteria isso:
for (auto i = c.begin(); i != c.end(); ++i) { ...
nisso:
for (auto i = c.rbegin(); i != c.rend(); ++i) { ...
Eu quero converter isso:
for (auto& i: c) { ...
para isso:
for (auto& i: std::magic_reverse_adapter(c)) { ...
Existe uma coisa dessas ou eu mesmo tenho que escrever?
c++
c++11
ranged-loops
Alex B
fonte
fonte
begin
paraend
ou para lidar com iteradores de fluxo e afins. Os algoritmos de alcance seriam ótimos, mas são realmente apenas açúcar sintático (exceto a possibilidade de avaliação lenta) sobre algoritmos de iterador.template<typename T> class reverse_adapter { public: reverse_adapter(T& c) : c(c) { } typename T::reverse_iterator begin() { return c.rbegin(); } typename T::reverse_iterator end() { return c.rend(); } private: T& c; };
Ele pode ser melhorado (adicionandoconst
versões, etc.) mas funciona:vector<int> v {1, 2, 3}; reverse_adapter<decltype(v)> ra; for (auto& i : ra) cout << i;
impressões321
template<typename T> reverse_adapter<T> reverse_adapt_container(T &c) {return reverse_adapter<T>(c);}
Então você pode usar apenasfor(auto &i: reverse_adapt_container(v)) cout << i;
para iterar.parallel_for
seria para isso, com uma condição ainda mais forte de "não ligo para que ordem", se fosse incorporada ao padrão de alguma forma. Claro que poderia ter um açúcar sintático baseado em gama também :-)Respostas:
Na verdade Impulso tem como adaptador:
boost::adaptors::reverse
.fonte
Na verdade, no C ++ 14, isso pode ser feito com muito poucas linhas de código.
Essa idéia é muito semelhante à solução do @ Paul. Devido a coisas que faltam no C ++ 11, essa solução é um pouco desnecessariamente inchada (além de definir os cheiros std). Graças ao C ++ 14, podemos torná-lo muito mais legível.
A principal observação é que os loops for-range baseados em intervalo funcionam confiando
begin()
eend()
para adquirir os iteradores do intervalo. Graças à ADL , não é necessário definir seu costumebegin()
eend()
no espaço de nome std ::.Aqui está uma solução de amostra muito simples:
Isso funciona como um encanto, por exemplo:
imprime como esperado
NOTA
std::rbegin()
,std::rend()
estd::make_reverse_iterator()
ainda não estão implementadas no GCC-4.9. Escrevo esses exemplos de acordo com o padrão, mas eles não seriam compilados no g ++ estável. No entanto, adicionar stubs temporários para essas três funções é muito fácil. Aqui está uma implementação de amostra, definitivamente não concluída, mas funciona bem o suficiente para a maioria dos casos:fonte
forward<T>
na suareverse
implementação.using namespace std
em um cabeçalho, o que não é uma boa ideia. Ou eu estou esquecendo de alguma coisa?Isso deve funcionar no C ++ 11 sem aumento:
fonte
std
espaço para nome tem um comportamento indefinido em 17.6.4.2.1.make_reverse_iterator
não está nostd
espaço para nome, portanto não entrará em conflito com a versão C ++ 14.Isso funciona para você:
fonte
por exemplo:
fonte
Se você pode usar o intervalo v3 , pode usar o adaptador de intervalo reverso,
ranges::view::reverse
que permite visualizar o contêiner ao contrário.Um exemplo de trabalho mínimo:
Veja DEMO 1 .
Nota: Conforme Eric Niebler , esse recurso estará disponível no C ++ 20 . Isso pode ser usado com o
<experimental/ranges/range>
cabeçalho. Em seguida, afor
declaração será assim:Veja DEMO 2
fonte
ranges::view
espaço para nome foi renomeado pararanges::views
. Então, useranges::views::reverse
.Se não estiver usando o C ++ 14, encontrarei abaixo a solução mais simples.
Demo .
Ele não funciona para os contêineres / tipos de dados (como matriz), que não tem
begin/rbegin, end/rend
funções.fonte
Você pode simplesmente usar o
BOOST_REVERSE_FOREACH
que itera para trás. Por exemplo, o códigogera a seguinte saída:
fonte