名前空間
変種
操作

可変長引数

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

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

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

省略符号の前のコンマは省略できる。 (C++26で非推奨)
// the function declared as follows
int printx(const char* fmt, ...);
int printx(const char* fmt...); // same as above, but deprecated since C++26
 
// may be called with one or more arguments:
printx("hello world");
printx("a=%d b=%d", a, b);
 
int printy(..., const char* fmt); // error: ... can only be the last parameter
int printz(...); // valid, but the arguments cannot be accessed portably

これは、パラメーター単独で省略符号であるのではなく、パラメーター宣言子の一部である省略符号によって示される関数のパラメーターパック展開とは異なる。パラメーターパック展開と「可変引数」省略符号の両方は、std::is_functionの場合のように、関数テンプレートの宣言に現れることがある。

(C++11以降)

目次

[編集] デフォルト引数の昇格

可変引数関数が呼び出されると、lvalue-to-rvalue、array-to-pointer、function-to-pointerの変換の後、可変引数リストの一部である各引数には、デフォルト引数の昇格として知られる追加の変換が適用される

(C++11以降)
  • float 引数は、浮動小数点昇格と同様に double に変換される。
  • boolcharshort、およびスコープのない列挙型は、整数昇格と同様に int またはより広い整数型に変換される。

非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...);   // template<class... Ts> void f3(Ts...) と同じ
void f2(auto, ...); // 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 ドキュメント - 可変引数
C ドキュメント - 暗黙の型変換
English 日本語 中文(简体) 中文(繁體)