C++で可変数の引数(可変長引数)を扱う方法
プログラミングをしていると、引数の個数があらかじめ決まっていない関数、つまり呼び出しのたびに異なる数のパラメータを受け取れる関数が必要になる場面があります。C/C++ではこのような状況に対応する仕組みが用意されており、要件に応じて可変個の引数を受け取る関数を自由に定義できます。以下に、そのような関数の定義例を示します。
int func(int, ... ) {
.
.
.
}
int main() {
func(1, 2, 3);
func(1, 2, 3, 4);
}
注目すべきは、関数func()の最後の引数が省略記号(ピリオド3つの「...」)になっている点です。また、省略記号の直前の引数は慣例として必ずint型にし、渡された可変引数の総数を表すようにします。この機能を利用するには、stdarg.hヘッダファイル(C++ではcstdarg)を読み込む必要があります。このヘッダには、可変引数を実装するための関数やマクロが定義されています。具体的な手順は以下の通りです。
関数の最後のパラメータを省略記号(...)として定義し、その直前のパラメータは必ずint型にして、引数の個数を表すようにします。
関数定義の中でva_list型の変数を作成します。この型はstdarg.hヘッダファイルで定義されています。
int型のパラメータとva_startマクロを使い、va_list変数を引数リストで初期化します。va_startマクロもstdarg.hヘッダファイルで定義されています。
va_argマクロとva_list変数を使って、引数リスト内の各項目へ順番にアクセスします。
va_endマクロを使って、va_list変数に割り当てられたメモリを解放します。
それでは、上記の手順に従って、可変個の引数を受け取り、その平均値を返すシンプルな関数を作成してみましょう。
サンプルコード
#include <iostream>
#include <cstdarg>
using namespace std;
double average(int num,...) {
va_list valist;
double sum = 0.0;
int i;
va_start(valist, num); // num個の引数のためにvalistを初期化
for (i = 0; i < num; i++) { // valistに割り当てられたすべての引数にアクセス
sum += va_arg(valist, int);
}
va_end(valist); // valist用に確保されたメモリを解放
return sum/num;
}
int main() {
cout << "Average of 2, 3, 4, 5 = "<< average(4, 2,3,4,5) << endl;
cout << "Average of 5, 10, 15 = "<< average(3, 5,10,15)<< endl;
}
実行結果
Average of 2, 3, 4, 5 = 3.5 Average of 5, 10, 15 = 10
補足:現代のC++における代替手段
上記の方法はC言語から引き継がれた古典的な手法ですが、型安全性の観点から注意が必要です。va_argマクロでは実際の型を指定するため、誤った型を指定すると未定義動作を引き起こす可能性があります。モダンなC++では、可変長テンプレート(variadic templates)やstd::initializer_listを使うことで、型安全に可変個の引数を扱えます。ただし、printfスタイルの関数を自作する場合やC言語との互換性が必要な場面では、今回紹介したstdargの手法が今でも広く使われています。
-
C++のCHAR_BITとは?意味と使い方を解説
CHAR_BITは、char型が持つビット数を表すマクロです。C++では「limits.h」ヘッダーファイル(C++では<climits>)で宣言されており、一般的な環境では1バイトが8ビットであることを示します。このマクロを利用することで、移植性の高いコードを書くことができます。環境に依存せずにchar型のビット数を取得できるため、ビット演算やデータサイズの計算に役立ちます。CHAR_BITの使用例以下は、C++でCHAR_BITを使用したサンプルコードです。CHAR_BITとsizeofを組み合わせてint型の全ビット数を求め、整数値を2進数形式で出力しています。#includ
-
C++で変数を初期化する方法をわかりやすく解説
C++における変数の初期化とはC++では、変数を使用する前に必ず初期化しておくことが重要です。未初期化の変数には不定値(ゴミ値)が入っており、そのまま使うと予期しない動作やバグの原因になります。変数の初期化には、主に「代入演算子を使う方法」と「コンストラクタを使う方法」の2つがあります。代入演算子による初期化最も基本的な方法は、代入演算子(=)を使って初期値を設定することです。int i = 0;コンストラクタによる初期化クラスや構造体のインスタンスは、コンストラクタに引数を渡して初期化できます。MyClass instance(1, Hello);自動的に初期化されるケース明示的に初期化しな