Skip to content

Last updated:2026-10-12

Printing 1-100 in C++ Without Loops

Let's set a condition for you: without using loops, print the numbers 1 to 100.

Using loops it would be easy — so how many ways can you think of?

Today let's use some clever C++ tricks to write this kind of code. Comments and shares are welcome~

This problem is actually very simple, but it covers many interview topics, including:

  • Template specialization and partial specialization, how to write recursive templates
  • CRTP
  • How to use std::copy, std::iota, and std::transform, and how each algorithm is implemented
  • Class static variables
  • and so on

1. Recursion

1-100 can be decomposed as 5*5*4. Use three functions to print it: function a does one cout and increments the variable by 1; function b nests a five times over; function c nests b five times over; finally, in the main function, nest c four times.

#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. Template Overloading

Use templates and specialization to handle it: when the iteration reaches 100, output only 100; otherwise output I, increment by 1, and recurse.

#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

Approach 3 builds on approach 2, refactoring it into CRTP style. Looks a bit baffling, doesn't it? Heh.

The struct below can be replaced with a class; here I'll describe it with classes. It's really just two classes. The first class, Print, is the parent: it prints the current I and calls the child class. The child class PrintDerived inherits from Print and passes itself to the parent. The child class is a specialized class that controls the recursion's termination.

#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. Class Static Variables

Create an array of Test objects with 100 elements; the static variable increments each time.

#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. Using the Algorithms Library

Use std::for_each — quick and dirty.

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. C++20 Ranges

Use C++20's std::views, printing while doing 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"));
}

This approach can be further adapted into another implementation using 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());

Comments