コンテンツにスキップ

最終更新:2026-10-12

C++ ループなしで 1-100 を出力

みなさんに 1 つの条件を課します:ループを使わずに、1〜100 の数字を出力してください。

ループを使えば簡単ですが、あなたは何通り思いつきますか?

今日は C++ のちょっとした小技を使って、このようなコードを書いてみます。コメントとシェアお待ちしています〜

この問題自体は非常にシンプルですが、多くの面接の論点を含んでいます。その中には次のものがあります:

  • テンプレートの特殊化・部分特殊化、再帰テンプレートの書き方
  • CRTP
  • std::copy、std::iota、std::transform の使い方と各アルゴリズムの実装
  • クラスの静的変数
  • など

1.再帰

1〜100 は 5*5*4 に分解でき、3 つの関数で出力します。関数 a は cout を 1 回行い、変数を 1 増やします。関数 b は a を 5 回入れ子にし、関数 c は b を 5 回入れ子にし、最後に main 関数の中で c を 4 回入れ子にします。

#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.テンプレートのオーバーロード

テンプレートと特殊化を使って処理します。反復が 100 に達したときは 100 だけを出力し、それ以外のときは I を出力し、+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

方式 3 は方式 2 をベースに、crtp プログラミングスタイルへ改造したものです。少し読めなくなってきましたね、ふふ。

下の struct は class に置き換えられますが、ここではクラスとして説明します。実際は 2 つのクラスです。最初のクラス Print は親クラスで、毎回の I を出力し、子クラスを呼び出します。子クラス PrintDerived は Print を継承し、自分自身を親クラスに渡します。子クラスはオーバーロードのためのクラスで、再帰の終了を制御します。

#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.クラスの静的変数

Test の配列を作成し、要素数は 100 とし、静的変数が毎回加算されていきます。

#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.アルゴリズムライブラリを使用

std::for_each を使えば単純粗暴に済みます。

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

C++20 の std::views を使用し、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"));
}

この方式をさらに改造すると、もう 1 つの実装があります。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());

関連トピック

コメント