web-dev-qa-db-ja.com

可変引数リストを受け入れる別の関数に可変引数を渡す

だから私は2つの関数があり、どちらも同じような引数を持っています

void example(int a, int b, ...);
void exampleB(int b, ...);

exampleexampleBを呼び出しますが、exampleBを変更せずに変数引数リストの変数を渡す方法はあります(これは既に他で使用されているため)。

92
Not Available

直接行うことはできません。 va_listをとる関数を作成する必要があります。

#include <stdarg.h>

static void exampleV(int b, va_list args);

void example(int a, int b, ...)
{
    va_list args;
    va_start(args, b);
    exampleV(b, args);
    va_end(args);
}

void exampleB(int b, ...)
{
    va_list args;
    va_start(args, b);
    exampleV(b, args);
    va_end(args);
}

static void exampleV(int b, va_list args)
{
    ...whatever you planned to have exampleB do...
    ...except it calls neither va_start nor va_end...
}
107

ここの池に石を投げるかもしれませんが、C++ 11の可変テンプレートを使用すればかなりうまくいくようです:

#include <stdio.h>

template<typename... Args> void test(const char * f, Args... args) {
  printf(f, args...);
}

int main()
{
  int a = 2;
  test("%s\n", "test");
  test("%s %d %d %p\n", "second test", 2, a, &a);
}

少なくとも、g++で動作します。

23

va_listを受け取るこれらの関数のバージョンを作成し、それらを渡す必要があります。例としてvprintfを見てください:

int vprintf ( const char * format, va_list arg );
15
tenfour

また、printfをラップしたかったので、役立つ答えが見つかりました。

printf/sprintfに可変数の引数を渡す方法

私はパフォーマンスにまったく興味がありませんでした(このコードはさまざまな方法で改善できると確信しています、お気軽に:))、これは一般的なデバッグ印刷専用ですので、これを行いました:

//Helper function
std::string osprintf(const char *fmt, ...)
{
    va_list args;
    char buf[1000];
    va_start(args, fmt);
    vsnprintf(buf, sizeof(buf), fmt, args );
    va_end(args);
    return buf;
}

これは次のように使用できます

Point2d p;

cout << osprintf("Point2d: (%3i, %3i)", p.x, p.y);
instead of for example:
cout << "Point2d: ( " << setw(3) << p.x << ", " << p.y << " )";

C++ ostreamsはいくつかの面で美しいですが、括弧、コロン、カンマなどの小さな文字列を数字の間に挿入してこのようなものを印刷したい場合、実際には恐ろしくなります。

4
Axel

ちなみに、多くのC実装には内部v?printfバリエーションがあり、IMHOはC標準の一部であるべきでした。正確な詳細は異なりますが、典型的な実装では、文字出力関数ポインタと何が起こるかを示す情報を含む構造体を受け入れます。これにより、printf、sprintf、fprintfはすべて同じ「コア」メカニズムを使用できます。たとえば、vsprintfは次のようになります。

 void s_out(PRINTF_INFO * p_inf、char ch)
 {
(*(p_inf-> destptr)++)= ch; 
 p_inf-> result ++; 
} 
 
 int vsprintf(char * dest、const char * fmt、va_list args)
 {
 PRINTF_INFO p_inf; 
 p_inf.destptr = dest; 
 p_inf.result = 0; 
 p_inf.func = s_out; 
 core_printf(&p_inf、fmt、args); 
} 

次に、core_printf関数は、出力される各文字に対してp_inf-> funcを呼び出します。出力関数は、コンソール、ファイル、文字列などに文字を送信できます。実装がcore_printf関数(および使用するセットアップメカニズム)を公開する場合は、あらゆる種類のバリエーションで拡張できます。

2
supercat

可能な方法は、#defineを使用することです。

#define exampleB(int b, ...)  example(0, b, __VA_ARGS__)
0
Shai

vsprintfをラップし、これがC++としてタグ付けされているというコメントに基づいて、これを行わないことをお勧めしますが、代わりにC++ iostreamを使用するようにインターフェイスを変更します。型の安全性やprintが処理できないアイテムを印刷できるなど、printf関数の行よりも利点があります。現在、いくつかの手直しにより、将来の痛みを大幅に軽減できます。

0
Mark B