14.07
2020
C++ tem várias opções de iteração. Desde o C++98 existe o algoritmo for_each disponível. Basicamente o que este algoritmo faz é executar uma função a todos os elementos contidos em um tipo iterável, tal como um std::vector, ou um std::map, dentre diversos outros.
Simplesmente Utilizando
No exemplo abaixo exploramos duas possibilidades do for_each. A primeira é aplicar uma função unária a cada elemento. A segunda é aplicar um classe que sobrecarregue o operator () (na verdade tem que ser uma CopyConstructor ou MoveConstructor, mas vamos deixar mais simples por enquanto).
#include <algorithm>
#include <iostream>
#include <list>
class sumop {
protected:
int total;
public:
sumop(int start = 0) { total = start; }
void operator() (int i) {
total += i;
std::cout << total << " ";
}
int getTotal() { return total; }
};
void coutfn(int i) {
std::cout << i << " ";
}
int main() {
std::list<int> l;
sumop sum(0);
l.puh_back(11);
l.push_back(12);
l.push_back(13);
std::cout << "l: ";
std::for_each(l.begin(), l.end(), coutfn);
std::cout << std::endl;
std::for_each(l.begin(), l.end(), sum);
std::cout << std::endl;
std::cout << "sum l: " << sum.getTotal() << std::endl;
}
No primeiro for_each aplicamos uma função que imprime cada membro do std::list. No segundo somamos cada membro do std::list, mas a saída do programa é a seguinte:
l: 11 12 13
11 23 36
sum l: 0
Note que a soma não funcionou. Vamos consultar a documentação.
O que Deu Errado?
Note na documentação que a declaração do for_each as classes CopyConstructor e MoveConstructor são passadas por valor, e não por referência. Por consequência a instância de sumop que efetua a somatória é diferente da instância sumop que é declarada dentro do main().
Uma opção para resolver esse problema, sem utilizar outro algoritmo é utilizar uma variável estática. Assim:
#include <algorithm>
#include <iostream>
#include <list>
class sumop {
protected:
static int total;
public:
static void reset() {
total = 0;
}
void operator() (int i) {
total += i;
std::cout << sumop::total << " ";
}
static int getTotal() {
return total;
}
};
int sumop::total = 0;
void coutfn(int i) {
std::cout << i << " ";
}
int main() {
std::list<int> l;
sumop sum;
l.push_back(11);
l.push_back(12);
l.push_back(13);
std::cout << "l: ";
std::for_each(l.begin(), l.end(), coutfn);
std::cout << std::endl;
sumop::reset();
std::for_each(l.begin(), l.end(), sum);
std::cout << std::endl;
std::cout << "sum l: " << sumop::getTotal() << std::endl;
}
E a saída apropriadamente:
l: 11 12 13
11 23 36
sum l: 36
As possibilidades do for_each são muito grandes, mas é necessário prestar atenção não somente na documentação do for_each, mas de qualquer outra função, método, ou API para evitar falhas desse tipo.
Comentários
[…] loop também já foi abordado anteriormente no Lab C++. Basicamente é um loop de iteração em containers e arrays. Sua sintaxe é a […]