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());
Related Topics¶
- Six Ways to Split Strings in C++ | C++那些事
- CPython Extension Development Notes | C++那些事
- libcurl C++ Development Notes | C++那些事
- How to Read Open Source C++ Code | C++那些事
- An Interesting Piece of C++ Code | C++那些事