2012-01-13 3 views
1

私は、スクリプト言語(Lua)で関数を呼び出すことをより簡単にすることを可能にする何かに取り組んでいます.1つは、可変引数を使用することでした。バリデーション引数をコンテナクラスにキャストする方法は?

Call(int count, ...) 

Call(const char* args, ...) 

printfのような:それを行うには、2つの方法があります。私は最初のものが維持するのがやや簡単だと思ったので、引数の型を管理するラッパーを作ってやってみました。それは次のようになります。

class ArgWrapper 
{ 
public: 
    ArgWrapper(); 

    ArgWrapper(const int& v) { val.i = v; type = INT; } 
    ArgWrapper(const bool& v) { val.b = v; type = BOOL; } 
    ArgWrapper(const float& v) { val.f = v; type = FLOAT; } 
    ArgWrapper(const double& v) { val.d = v; type = DOUBLE; } 

    operator int() { return val.i; } 
    operator bool() { return val.b; } 
    operator float() { return val.f; } 
    operator double() { return val.d; } 

    enum { 
     INT, 
     BOOL, 
     FLOAT, 
     DOUBLE 
    } type; 

    union 
    { 
     int i; 
     bool b; 
     float f; 
     double d; 
    } val; 
}; 

これは結構な動作しますが、私は実際にvaradic引数の建設で、この作品を作るしようとすると、それは値が実際にキャストされていないことが判明します。ごみで

void printArgs(int c, ArgWrapper...) 
{ 
    va_list ap; 
    va_start(ap, c); 

    for (int i = 0; i < c; i++) 
    { 
     ArgWrapper arg = va_arg(ap, ArgWrapper); 
     if (arg.type == arg.INT) std::cout << "integer - " << (int)arg << std::endl; 
     if (arg.type == arg.BOOL) std::cout << "boolean - " << std::boolalpha << (bool)arg << std::endl; 
     if (arg.type == arg.FLOAT) std::cout << "float - " << (float)arg << std::endl; 
     if (arg.type == arg.DOUBLE) std::cout << "double - " << (double)arg << std::endl; 
    } 

    va_end(ap); 
} 

... 

printArgs(4, 1337.0f, 18, 37.0, true); 

以上の結果、これは完全に正常に動作している間:

printArgs(4, (ArgWrapper)1337.0f, (ArgWrapper)18, (ArgWrapper)37.0, (ArgWrapper)true); 

は、どのように私は、各可変長引数が同じ共通の型を持っている必要があることを指定するのですか?

答えて

4

Cスタイルの省略記号...を使用する可変引数はどのような方法でも型情報を保持しないため、C++ 03を使用するとできません。このため、printf()のようなものはフォーマット指定子を使用します。なぜなら、何をキャストすべきかを知る方法を必要とするからです。

C++ 11を使用することができるときは、すぐにVariadicテンプレートを使用して、ArgWrapperのようなヘルパーを不要にする必要があります。

0

とき、あなたはC++ 11から初期化子リスト機能をサポートしているC++コンパイラを持っている場合は、この缶を

#include <initializer_list> 

void printArgs(std::initializer_list<ArgWrapper> args) { 
    for (const ArgWrapper *arg = args.begin(), *end = args.end; arg != end; ++arg) { 
    /* process arg */ 
    } 
} 

としてあなたprintArgs関数を記述し、

printArgs({ 4, 1337.0f, 18, 37.0, true }); 

のようにそれを呼び出すことができますバリデーションテンプレートよりも簡単なルートになることがあります。救助へ

0

可変引数テンプレート:

template <typename ...Args> 
R call(int n, Args &&... args) 
{ 
    return printArgs(n, ArgWrapper(std::forward<Args>(args))...); 
} 

これはあなたのprintArgs機能は、実際にCスタイルの可変長引数を使用しなければならないと仮定しています。これには理由があります。すべてがC++の場合、いくつかの選択肢があります。

関連する問題