Namespaces
Variants

Variadic arguments

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

関数が任意の数の追加引数を受け入れることを可能にします。

関数は、その パラメータリスト の最後のパラメータが省略記号( ... )である場合、可変引数関数となります。

省略記号の前のコンマは省略可能です。 (C++26で非推奨)
// 以下のように宣言された関数
int printx(const char* fmt, ...);
int printx(const char* fmt...); // 上記と同じだが、C++26以降非推奨
// 1つ以上の引数で呼び出し可能:
printx("hello world");
printx("a=%d b=%d", a, b);
int printy(..., const char* fmt); // エラー: ... は最後のパラメータでのみ使用可能
int printz(...); // 有効だが、引数に移植性を持ってアクセスできない

これは parameter pack の関数パラメータパック展開とは異なります。パラメータパック展開はパラメータ宣言子の一部としての省略記号で示されるのに対し、「可変引数」の省略記号は単独のパラメータとして機能します。パラメータパック展開と「可変引数」の省略記号はどちらも関数テンプレートの宣言に現れる可能性があり、 std::is_function の場合のように使用されます。

(C++11以降)

目次

デフォルト引数プロモーション

可変個引数関数が呼び出されると、左辺値から右辺値、配列からポインタ、関数からポインタへの 変換 の後、可変個引数リストの一部である各引数は デフォルト引数プロモーション として知られる追加の変換を受けます:

(C++11以降)

Non-PODクラス型 (C++11まで) スコープ付き列挙型および、適格な非自明なコピーコンストラクタ、適格な非自明なムーブコンストラクタ、または非自明なデストラクタを持つクラス型 (C++11以降) は、実装定義のセマンティクスを持つ潜在的に評価される呼び出しにおいて条件付きでサポートされる(これらの型は常に 評価されない呼び出し でサポートされる)。

可変個引数パラメータは オーバーロード解決 において最も低い優先順位を持つため、 SFINAE においてキャッチオールのフォールバックとして一般的に使用されます。

可変個引数を使用する関数本体内部では、これらの引数の値は <cstdarg> ライブラリ機能 を使用してアクセスできます:

定義済みヘッダ <cstdarg>
可変個引数関数の引数へのアクセスを有効にする
(関数マクロ)
次の可変個引数関数の引数にアクセスする
(関数マクロ)
(C++11)
可変個引数関数の引数のコピーを作成する
(関数マクロ)
可変個引数関数の引数の走査を終了する
(関数マクロ)
va_start , va_arg , va_end , および va_copy が必要とする情報を保持する
(typedef)

省略記号の前の最後のパラメータが参照型である場合、または 互換性のある型 でない型(デフォルト引数プロモーションによって生じる型と互換性のない型)である場合、 va_start マクロの動作は未定義です。

パック展開 または ラムダキャプチャ によって生成されたエンティティが va_start の最後のパラメータとして使用される場合、プログラムは不適格であり、診断は不要である。

(C++11以降)

代替案

  • 可変引数テンプレート は可変個の引数を取る関数を作成するためにも使用できます。これらは多くの場合、より良い選択肢となります。なぜなら、引数の型に制限を課さず、整数および浮動小数点のプロモーションを行わず、型安全であるためです。
  • すべての可変引数が共通の型を共有する場合、 std::initializer_list は(異なる構文ではありますが)可変引数にアクセスするための便利なメカニズムを提供します。ただしこの場合、 std::initializer_list は要素へのconstポインタのみを提供するため、引数を変更することはできません。
(C++11以降)

注記

Cプログラミング言語ではC23まで、省略記号パラメータの前に少なくとも1つの名前付きパラメータが存在しなければならないため、 R printz ( ... ) ; はC23まで有効ではありません。C++では、この形式はそのような関数に渡された引数にアクセスできないにもかかわらず許可されており、 SFINAE におけるフォールバックオーバーロードとして一般的に使用され、 オーバーロード解決 における省略記号変換の最低優先順位を利用しています。

この可変引数の構文は、1983年のC++で、省略記号の前のコンマなしで導入されました。C89がC++から関数プロトタイプを採用した際、コンマを必要とする構文に置き換えられました。互換性のため、C++98はC++スタイルの f ( int n... ) とCスタイルの f ( int n, ... ) の両方を受け入れます。元のC++スタイルの文法はC++26以降非推奨となっています。

コンマを使用して省略記号が可変引数テンプレートではなく可変引数関数を表すように省略関数テンプレートを記述できます:

void f1 ( auto ... ) ; // same as template<class... Ts> void f3(Ts...)
void f2 ( auto , ... ) ; // same as template<class T> void f3(T, ...)

(C++20以降)

不具合報告

以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。

DR 適用バージョン 公開時の仕様 修正後の仕様
CWG 506 C++98 非PODクラス引数を
エリプシスに渡すと未定義動作となった
当該引数の渡しは条件付きサポートとなり
実装定義のセマンティクスを持つ
CWG 634 C++98 条件付きサポートのクラス型により
一部のSFINAEイディオムが機能しなかった
未評価コンテキストでは常にサポートされる
CWG 2247 C++11 パラメータパックやラムダキャプチャを
va_start に渡す制限がなかった
不適格な形式となり
診断不要となる
CWG 2347 C++11 スコープ付き列挙型をエリプシスに渡した場合に
デフォルト引数プロモーションの対象となるか不明確だった
スコープ付き列挙型の渡しは条件付きサポートとなり
実装定義のセマンティクスを持つ

関連項目

C documentation for Variadic arguments
C documentation for Implicit conversions