Ir para o conteúdo

Ú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"));
}
Continuando a adaptar esse modo, há ainda outra implementação, com std::transform.

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

Comentários