Última atualização:2026-10-12
Imprimir de 1 a 100 em C++ sem laços¶
Vou propor uma condição para vocês: sem usar laços, imprima os números de 1 a 100.
Com laços seria muito simples; então, de quantos métodos você consegue lembrar?
Hoje vou mostrar alguns truques espertos de C++ para escrever esse código; fique à vontade para comentar e compartilhar~
Esse exercício é na verdade bem simples, mas cobre muitos pontos de entrevista, entre eles:
- Especialização de templates e especialização parcial, como escrever templates recursivos
- CRTP
- Como usar std::copy, std::iota e std::transform, e a implementação de cada algoritmo
- Variáveis estáticas de classe
- entre outros
1.Recursão¶
1-100 pode ser decomposto em 5*5*4: usa-se três funções para imprimi-lo; a função a faz um cout e incrementa a variável em 1, a função b aninha a em 5 níveis, a função c aninha b em 5 níveis e, por fim, na função main, aninha-se c em 4 níveis.
#include <iostream>
int a(int n) {
std::cout << n++ << std::endl;
return n;
}
int b(int n) { return a(a(a(a(a(n))))); }
int c(int n) { return b(b(b(b(b(n))))); }
int main() {
c(c(c(c(1))));
return 0;
}
2.Sobrecarga com templates¶
Usa-se templates e especialização: quando a iteração chega a 100, imprime apenas 100; caso contrário, imprime I e continua a recursão com +1.
#include <iostream>
template <int I>
struct JustPrint : public JustPrint<I + 1> {
JustPrint() : JustPrint<I + 1>() { std::cout << I << " "; }
};
template <>
struct JustPrint<100> {
JustPrint<100>() { std::cout << 1 << " "; }
};
int main() { JustPrint<1> j; }
3.CRTP¶
O modo 3 baseia-se no modo 2, transformando-o no estilo de programação crtp — ficou meio difícil de entender, hein?
O struct abaixo pode ser substituído por class; aqui descrevo com classes. São, na verdade, duas classes: a primeira, Print, é a classe-mãe, imprime o I de cada vez e chama a classe-filha; a classe-filha PrintDerived herda de Print e passa a si mesma para a classe-mãe; a classe-filha é uma classe sobrecarregada que controla o fim da recursão.
#include <iostream>
template <typename Derived, int I>
struct Print {
Print() {
std::cout << I << " ";
Derived::next();
}
};
template <int I>
struct PrintDerived : public Print<PrintDerived<I>, I> {
static void next() { PrintDerived<I + 1>(); }
};
template <>
struct PrintDerived<100> : public Print<PrintDerived<100>, 100> {
static void next() {}
};
int main() {
PrintDerived<1> j;
return 0;
}
4.Variável estática de classe¶
Cria-se um array de Test com 100 elementos; a variável estática acumula a cada vez.
#include <iostream>
using namespace std;
class Test {
static int i;
public:
Test() { cout << ++i << endl; }
};
int Test::i;
int main() {
Test a[100];
return 0;
}
5.Usar a biblioteca de algoritmos¶
Usa-se std::for_each, simples e direto.
int main() {
std::vector<int> l(100);
std::iota(l.begin(), l.end(), 1);
std::for_each(l.begin(), l.end(), [](int& n) { std::cout << n << std::endl; });
return 0;
}
6.ranges do C++20¶
Usa-se o std::views do C++20, imprimindo durante o std::copy.
#include <iostream>
#include <iterator>
#include <ranges>
int main() {
auto numbers = std::views::iota(1, 100 + 1);
std::copy(numbers.begin(), numbers.end(), std::ostream_iterator<int>(std::cout, "\n"));
}
auto range = std::views::transform(std::ranges::iota_view{1, 101}, [](const auto& x) {
std::cout << x << std::endl;
return x;
});
std::vector<int> a(range.begin(), range.end());
Tópicos relacionados¶
- Seis métodos de divisão de strings em C++ | C++那些事
- Notas sobre desenvolvimento de extensões CPython | C++那些事
- Notas de desenvolvimento com libcurl em C++ | C++那些事
- Como ler código C++ open source | C++那些事
- Um trecho de código C++ interessante | C++那些事