C++の可変長引数を完全解説!初心者でもわかる関数の引数を増やす方法
生徒
「C++で関数を作るとき、渡したいデータの数が日によって違う場合はどうすればいいですか?」
先生
「そんなときは『可変長引数(かへんちょうひきすう)』という便利な仕組みを使いますよ。」
生徒
「カヘンチョウ……?名前は難しそうですが、データの数が決まってなくても大丈夫なんですか?」
先生
「はい。必要な分だけ自由にデータを詰め込める魔法のポケットのようなものです。一緒に見ていきましょう!」
1. 可変長引数とは?「数が決まっていない」の正体
C++の可変長引数(かへんちょうひきすう)とは、関数を呼び出すときに渡すデータの数(引数の数)を、あらかじめ固定せずに自由に決められる仕組みのことです。プログラミング未経験の方には、「買い物かご」をイメージしてもらうと分かりやすいでしょう。
普通の関数は、卵を2個だけ入れる専用のパックのようなものです。しかし、可変長引数を使った関数は、卵を3個入れても、10個入れても、あるいは1個も入れなくても受け入れてくれる柔軟なカゴなのです。この仕組みを理解することで、複数の数値を一度に合計したり、たくさんの文字を一度に表示したりするプログラムが、たった一つの関数で書けるようになります。
2. initializer_listを使った簡単な書き方
現代のC++(C++11以降)で最も推奨される、初心者にも優しい方法がinitializer_list(イニシャライザ・リスト)を使う方法です。これは、同じ種類のデータを「波括弧 { } 」で囲ってまとめて渡す手法です。
まずは、いくつ数字を渡しても、そのすべてを合計して表示するプログラムを見てみましょう。パソコンを触ったことがない方でも、この「まとめて渡す」感覚を掴んでみてください。
#include <iostream>
#include <initializer_list>
// いくつでも整数を受け取って合計を表示する関数
void sumAll(std::initializer_list<int> numbers) {
int total = 0;
// 受け取った数字を順番に取り出して足していく
for (int n : numbers) {
total += n;
}
std::cout << "合計は: " << total << std::endl;
}
int main() {
sumAll({1, 2, 3}); // 3つの数字を渡す
sumAll({10, 20, 30, 40, 50}); // 5つの数字を渡す
return 0;
}
合計は: 6
合計は: 150
このコードの素晴らしいところは、関数の中身を書き換えることなく、使う側が自由にデータの数を変えられる点にあります。
3. 難しいけど強力!可変長引数テンプレート
さらに高度な方法として、可変長引数テンプレート(バリアディック・テンプレート)があります。これは、数字だけでなく、文字や小数など「種類の違うデータ」をいくつでも混ぜて渡せる、まさに究極の柔軟性を持った機能です。
少し書き方に特徴がありますが、これは「データのパック」を一つずつ解いていくようなイメージで作ります。専門用語では「再帰(さいき)」という考え方を使いますが、初心者のうちは「魔法の呪文で一つずつ取り出しているんだな」と理解しておけば十分です。
#include <iostream>
// 最後に呼び出される空の関数(これがないと止まらない)
void printMixed() {
std::cout << "--- 終了 ---" << std::endl;
}
// どんな型でも、いくつでも受け取れるテンプレート関数
template<typename First, typename... Rest>
void printMixed(First f, Rest... r) {
std::cout << "データ: " << f << std::endl; // 最初の一個を表示
printMixed(r...); // 残りのパックをまた自分に渡す
}
int main() {
printMixed(100, "こんにちは", 3.14); // 整数、文字列、小数を混ぜて渡す
return 0;
}
データ: 100
データ: こんにちは
データ: 3.14
--- 終了 ---
4. パラメータパックという概念を覚えよう
先ほどのプログラムに出てきた「...」という3つの点は、プログラミングの世界でパラメータパックと呼ばれます。これは、複数の引数をひとまとめにした「未開封の段ボール箱」のようなものです。
この段ボール箱をそのまま使うことはできません。中身を確認するためには、一つずつ取り出すか、特定のルールで展開(パックを開封)する必要があります。C++では、この「...」を使うことで、関数の作り手が「ここには何個データが来るか分からないけれど、全部まとめて受け取るよ」という意思表示をしているのです。一見すると不思議な記号ですが、Googleの検索エンジンなどでも、こうした柔軟な仕組みが裏側で活躍しています。
5. 昔ながらの「printf」形式の可変長引数
C++の元となった「C言語」から引き継がれている、最も古い可変長引数の仕組みもあります。これは<cstdarg>というライブラリを使う方法です。現在のC++ではあまり推奨されませんが、古いプログラムを読み解くために知識として知っておく価値はあります。
この方法では、データの数を最初に教える必要があったり、データの種類を間違えるとパソコンがパニックを起こしたりするため、少し注意が必要です。現代的なC++を学ぶ皆さんは、まずは「initializer_list」をマスターすることをお勧めします。
#include <iostream>
#include <cstdarg>
// 最初の引数に「データの個数」を指定する古いスタイル
void oldStylePrint(int count, ...) {
va_list args;
va_start(args, count); // 準備開始
for (int i = 0; i < count; ++i) {
int val = va_arg(args, int); // 整数として一つ取り出す
std::cout << "値: " << val << " ";
}
va_end(args); // 終了処理
std::cout << std::endl;
}
int main() {
oldStylePrint(3, 10, 20, 30); // 最初に「3個あるよ」と教える
return 0;
}
値: 10 値: 20 値: 30
6. 可変長引数を使うメリットと活用シーン
なぜデータの数を固定しない方がいいのでしょうか?最大のメリットは、「プログラムの柔軟性が劇的に上がる」ことです。例えば、ログ(実行記録)を残すプログラムを作るとき、エラーメッセージだけを出すこともあれば、エラーメッセージと一緒にエラー番号や発生時刻も出したいときがあります。これらを別々の関数で作るのは大変ですが、可変長引数なら一つで済みます。
また、計算ソフトで「選択したセルすべての合計を出す」といった機能も、ユーザーが何個セルを選ぶか予想できません。こうした「予測不能な数」を扱うときに、可変長引数は真価を発揮します。ブログやWebサイトの検索機能などでも、複数のキーワードをまとめて処理する際によく似た仕組みが使われています。
7. 初心者がハマりやすい注意点
可変長引数は非常に強力ですが、使いすぎには注意が必要です。一番の欠点は、「どんなデータでも受け取れてしまうため、間違いに気づきにくい」という点です。普通の関数であれば、数字を入れるべき場所に文字を入れると、パソコンが「間違っていますよ!」と教えてくれます。しかし、可変長引数テンプレートなどでは、何でも受け入れてしまうため、後から思わぬミス(バグ)が見つかることがあります。
まずは、今回最初に紹介した「initializer_list」のように、「同じ種類のデータを、好きな数だけ渡す」というシンプルな使い方から慣れていきましょう。安全にプログラムを書くコツは、自由すぎる機能に少しだけ制限をかけて使うことなのです。
8. 実践例:平均値を求める関数を作ってみよう
最後に、学んだ知識を活かして、渡された数字の平均値を計算する関数を作ってみましょう。ここでは、データの個数を自動で数えてくれる機能を使います。これを使えば、3つのテストの平均も、10個のデータの平均も、自由自在に計算できます。
#include <iostream>
#include <initializer_list>
// 平均値を計算して表示する関数
void printAverage(std::initializer_list<double> scores) {
if (scores.size() == 0) return; // 何もなければ何もしない
double sum = 0;
for (double s : scores) {
sum += s;
}
// scores.size() でデータの個数が分かる
std::cout << "平均点は: " << sum / scores.size() << "点です。" << std::endl;
}
int main() {
// 3人のテスト結果
printAverage({80.0, 75.5, 90.0});
// 5人のテスト結果
printAverage({60, 70, 80, 90, 100});
return 0;
}
平均点は: 81.8333点です。
平均点は: 80点です。
このように、可変長引数を使えば「汎用性(はんようせい)」、つまり色々な場面で使い回せる非常に便利なプログラムが作れるようになります。C++の関数の世界が、これで一気に広がりましたね!