CおよびC++の可変長引数プログラミング

最終更新: 2022-09-05 18:24:42 +0800 +0800
原文は英語で書かれています。あなたはAI翻訳版を読んでいます。

C++の可変長テンプレートは、すべての引数の型と個数を保持します。Cの省略記号関数はその情報を消去するため、型の解釈と引数個数の管理が呼び出し側に移ります。新しい型付きインターフェースには、C++のパックを優先してください。

パック、展開、畳み込み #

テンプレートパラメータパックと関数パラメータパックには、0個以上の要素を含めることができます。パック展開は、要素ごとにパターンを1回適用します。

cpp
#include <utility>

template <class Function, class... Ts>
decltype(auto) invoke(Function&& function, Ts&&... values) {
    return std::forward<Function>(function)(std::forward<Ts>(values)...);
}

template <class... Ts>
auto sum(Ts... values) {
    return (0 + ... + values); // binary left fold; 0 is the empty-pack identity
}

std::forwardは、各転送参照について推論された値カテゴリを保持します。引数のライフタイムは延長しないため、呼び出し先は通常の参照および所有権の契約に従う必要があります。

展開は、テンプレート引数リスト、関数引数、基底指定子リスト、初期化子、ラムダキャプチャ、その他の文法で定義されたコンテキストで行われます。入れ子または同時の展開には、互換性のある長さのパックが必要です。

(values + ...)のような単項畳み込みでは、演算子に言語で定義された空の恒等元がない限り、空でないパックが必要です。空の入力に意味がある場合は、二項畳み込みで明示的な恒等元を指定してください。意味がない場合は、制約によって空の入力を拒否してください。

cpp
template <class... Ts>
requires (sizeof...(Ts) > 0)
auto product(Ts... values) {
    return (... * values);
}

Cの可変長引数関数 #

...で宣言されたC関数は、va_list、va_start、va_arg、va_copy、va_endを通じて名前のない引数を読み取ります。宣言には個数のメタデータも型のメタデータもありません。したがって、個数パラメータ、書式文字列、または文書化されたセンチネルはAPIコントラクトの一部です。

c
#include <stddef.h>
#include <stdarg.h>

int sum_ints(size_t count, ...) {
    va_list arguments;
    va_start(arguments, count);
    int result = 0;
    for (size_t i = 0; i < count; ++i)
        result += va_arg(arguments, int);
    va_end(arguments);
    return result;
}

デフォルト引数昇格は...全体に適用されます。floatはdoubleになり、intより狭い整数型はintまたはunsigned intに昇格します。va_argは、その位置で想定される昇格後の互換型を要求する必要があります。誤った型の読み取り、va_endの省略、提供された引数を超えた読み取り、または存在しないセンチネルへの依存は未定義動作です。Cの可変長引数は、ABI互換性のため、または正確な規約をすでに課している書式処理などのインターフェースにのみ使用してください。

コメント

GitHub で閲覧・コメントする(投稿にはログインが必要です)