As funções Lambda são funções anônimas, que não tem nome e pode ser anexada à uma variável ou outra função, e podem ser declaradas em qualquer parte do código e a partir desse ponto, pode ser usada quantas vezes for necessárias, e podemos passar uma lista de variáveis externas que queremos trabalhar dentro da nossa função. E elas também não precisam ser prototipadas (declaradas) inicialmente no código, antes do main.
As funções Lambda tem essa estrutura: [capturaDeVariaveis](parâmetros)->tipoDeRetorno {corpoDaFuncao};
.
Basicamente, criamos uma declaração Lambda assim:
int main() {
[](){}; // Isso já é uma função Lambda, definida pelos colchetes.
return 0;
}
Para exibir algo, atribuímos a Lambda à uma variável assim, e usamos como um método, assim:
int main() {
auto mensagem = [](){cout << "Introdução às Lambdas em C++!" << endl;};
mensagem();
return 0;
}
Veja um exemplo de uso de função com parâmetros e retorno:
int main() {
auto maior = [](int n1, int n2)->int{return (n1 > n2) ? n1 : n2;};
cout << maior(2, 6) << endl;
return 0;
}
A função Lambda não tem nome, mas como está associada à uma variável, ela pode ser invocada como uma função.
Podemos usar um vector para podemos passar quantidades diferentes de parâmetros, por exemplo:
int main() {
auto maior = [](vector<int> n)->int { // Importe vector
auto m = 0;
for(int x: n) {
m = (m > x) ? m : x;
}
return m;
};
cout << maior({9, 8, 2, 10, 45, 20, 5, 34, 12}) << endl;
return 0;
}
No caso acima, com o uso de vector, podemos inserir a quantidade de números que quisermos de forma dinâmica.
A captura de variáveis pode ser feita de tal forma:
int main() {
int x1, x2, x3, x4;
x1 = 10;
x2 = 5;
x3 = 2;
x4 = 12;
auto soma = [x1, x2, x3, x4]()->int{return x1 + x2 + x3 + x4;};
cout << soma() << endl;
return 0;
}
Ou colocando o símbolo de =
na captura de variáveis, que somará todas as variáveis do escopo, assim:
int main() {
int x1, x2, x3, x4;
x1 = 10;
x2 = 5;
x3 = 2;
x4 = 12;
auto soma = [=]()->int{return x1 + x2 + x3 + x4;};
cout << soma() << endl;
return 0;
}
Pode ser utilizado o igual no Lambda com argumentos também, dessa forma:
int main() {
int x1, x2, x3, x4;
x1 = 10;
x2 = 5;
x3 = 2;
x4 = 12;
auto maior = [=](vector<int> n)->int { // Importe vector
auto m = 0;
for(int x: n) {
m = (m > x) ? m : x;
}
return m;
};
cout << maior({1, 2, 3, 4, 5, 6, 7, 8, 9}) << endl;
return 0;
}
Podemos fazer a soma assim:
int main() {
auto soma = [](vector<int> n)->int { // Importe vector
auto s = 0;
for(int x: n) {
s += x;
}
return s;
};
cout << soma({1, 2, 3, 4, 5, 6, 7, 8, 9}) << endl;
return 0;
}
Seguindo a mesma lógica do C, só poderíamos definir constantes definindo uma macro no cabeçalho, por exemplo:
#include <iostream>
#define PI 3.141592
using namespace std;
int main() {
cout << PI << endl;
return 0;
}
Mas no C++ podemos ter constantes, usando a palavra const
antes do atributo e inicializando ela:
#include <iostream>
using namespace std;
int main() {
const double PI = 3.141592;
cout << PI << endl;
return 0;
}
PS: O const pode ser usado também em funções e métodos, desde que estes não façam alterações em variáveis ou atributos.
O pair se diferencia dos outros tipos de contâineres, por permitir sempre armazenar um par de dados, tipo um int e um string, ou um bool e um int, uma classe e um char, e etc.
Inicialmente, inclua a biblioteca utility, e coloque esse código:
pair<int, string> par(10, "Teste"); // Inclua utility
cout << par.first << " - " << par.second << endl;
Como vimos acima, o objeto pair foi definido como o primeiro sendo int e o segundo string, dessa forma, podemos exibir os elementos usando os atributos first e second, respectivamente.
Podemos também fazer sem inicializar o pair, assim:
pair<int, string> par;
par.first = 100;
par.second = "Cursos";
cout << par.first << " - " << par.second << endl;
Para declarar vetores de pair, fazemos assim:
const int TAM = 3;
pair<int, string> pares[TAM];
pares[0].first = 100;
pares[0].second = "Cursos";
pares[1].first = 200;
pares[1].second = "C++";
pares[2].first = 300;
pares[2].second = "Pair";
Podemos usar também o make_pair para facilitar a criação de pares:
const int TAM = 3;
pair<int, string> pares[TAM];
pares[0] = make_pair(100, "Cursos");
pares[1] = make_pair(200, "C++");
pares[2] = make_pair(300, "Pair");
for(int i = 0; i < 3; i++) {
cout << pares[i].first << " - " << pares[i].second << endl;
}
PS: Podemos passar um pair dentro de outro pair, por exemplo:
pair<int, pair<string, double>> produtos[3];
produtos[0] = make_pair(10, make_pair("Mouse", 10.55));
produtos[1] = make_pair(20, make_pair("Teclado", 50.49));
produtos[2] = make_pair(30, make_pair("Monitor", 399.98));
for(int i = 0; i < 3; i++) {
cout << produtos[i].first << " - " << produtos[i].second.first << " - " << produtos[i].second.second << endl;
}
Pode ver que da forma acima, o pair externo tem seu first e seu second, e nesse second tem outro pair, quando chamamos atributos deles, usamos o second.first e o second.second, se o pair interno for o primeiro, é first.first e first.second. Esteja atento quanto à isso.
Claro que em C++ é mais interessante usar o vector, dessa forma:
vector<pair<int, string>> prod; // Importe vector
prod.push_back(make_pair(10, "Mouse"));
prod.push_back(make_pair(20, "Teclado"));
prod.push_back(make_pair(30, "Monitor"));
for(int i = 0; i < prod.size(); i++) {
cout << prod[i].first << " - " << prod[i].second << endl;
}
PS: Podemos usar o for it também:
for(auto i: prod) {
cout << i.first << " - " << i.second << endl;
}
O Map é um containers de associação de chave e valor, ele parece um pouco com o pair, mas ele associa o segundo elemento (valor) ao primeiro (chave).
Primeiro, inclua a biblioteca map, e coloque esse código:
map<int, string> prod; // Inclua map
No código acima, a chave é do tipo int, e o valor é string, o valor é associado à chave, mas eles podem ser de tipos diferentes, pode também receber structs, classes e etc., e podem ser usado com vector, como acontece com os pairs.
Para adicionar elementos, faça como se faz com um vetor:
map<int, string> prod; // Inclua map
prod[0] = "Mouse";
prod[1] = "Teclado";
prod[2] = "Monitor";
prod[3] = "Caixa";
for(int i = 0; i < 4; i++) {
cout << prod[i] << endl;
}
O que está dentro dos colchetes é a chave (no caso, int, poderia ser outro tipo, definido no map), e o valor associado a ela é o que está após o símbolo de atribuição.
Podemos exibir também dessa forma:
map<int, string> prod; // Inclua map
prod[0] = "Mouse";
prod[1] = "Teclado";
prod[2] = "Monitor";
prod[3] = "Caixa";
for(auto it = prod.begin(); it != prod.end(); it++) {
cout << it->first << " - " << it->second << endl;
}
Da forma acima, usando o first, imprime a chave, e o second imprime o valor, independente do tipo de ambos.
Pra simplificar, podemos usar o for it assim:
for(auto it: prod) {
cout << it.first << " - " << it.second << endl;
}
Mas o certo é usar o insert, onde inserimos os pares decladados no map (na mesma ordem dos tipos pré-definidos, utilizando o pair:
map<int, string> prod; // Inclua map
prod.insert(pair<int, string>(0, "Mouse")); // Inclua utility
prod.insert(pair<int, string>(1, "Teclado"));
prod.insert(pair<int, string>(2, "Monitor"));
prod.insert(pair<int, string>(3, "Caixa"));
for(auto it: prod) {
cout << it.first << " - " << it.second << endl;
}
Para apagar um índice, utilize o erase com o conteúdo da chave a ser apagada:
prod.erase(2);
PS: Lembrando que isso não é a posição do elemento, ele vai procurar o elemento com a chave 2, se eles forem enumerados com 10, 20, 30 e 40, ou for outro tipo na chave, como o char, ele não apagará a "posição 2" do map.
Para apagar todos os elementos do map, use o clear, assim:
prod.clear();
Temos também o find, que procura uma chave do map, e retorna o valor correspondente à esta:
map<int, string> prod; // Inclua map
map<int, string>::iterator itmap;
prod.insert(pair<int, string>(10, "Mouse")); // Inclua utility
prod.insert(pair<int, string>(20, "Teclado"));
prod.insert(pair<int, string>(30, "Monitor"));
prod.insert(pair<int, string>(40, "Caixa"));
prod.insert(pair<int, string>(50, "Microfone"));
prod.insert(pair<int, string>(60, "Gabinete"));
prod.insert(pair<int, string>(70, "Câmera"));
itmap = prod.find(30);
if(itmap == prod.end()) {
cout << "Produto não Encontrado!" << endl;
}
else {
cout << "Produto em Estoque: " << endl;
cout << "Código: " << itmap->first << endl;
cout << "Produto: " << itmap->second << endl;
cout << "----------------------------------" << endl;
}
Agora tente passar uma chave que não existe nesse mesmo find.
Podemos também excluir uma quantidade específica de produtos, usando o erase, dessa forma:
prod.erase(prod.begin(), prod.find(30));
PS: Ele não excluí o conteúdo da chave passada, e sim até antes dele.
Da forma acima, ele excluí da primeira posição até antes da especificada, mas podemos escolher uma faixa específica assim:
prod.erase(prod.find(30), prod.find(60));