C++ 如何将可变参数强制转换为容器类?

C++ 如何将可变参数强制转换为容器类?,c++,C++,我正在研究一种可以让我更容易用脚本语言(Lua)调用函数的方法,其中一个想法是使用可变参数。有两种方法可以做到这一点: Call( int count, ... ) 及 像printf。我认为第一个会更容易维护,所以我尝试制作一个包装器来管理参数类型。看起来是这样的: class ArgWrapper { public: ArgWrapper(); ArgWrapper( const int& v ) { val.i = v; type = INT; } Ar

我正在研究一种可以让我更容易用脚本语言(Lua)调用函数的方法,其中一个想法是使用可变参数。有两种方法可以做到这一点:

Call( int count, ... )

像printf。我认为第一个会更容易维护,所以我尝试制作一个包装器来管理参数类型。看起来是这样的:

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 );

如何指定每个可变参数应具有相同的公共类型?

当使用C++03时,不能这样做,因为使用C样式省略号的可变参数不以任何方式携带类型信息。这就是为什么像
printf()
这样的东西使用格式说明符的原因,因为它需要一种方法来知道将东西转换成什么


当您可以使用C++11时,应该立即使用可变模板,这会使任何类型的帮助程序(如ArgWrapper)变得不必要。

当您使用C++03时,您不能,因为使用C样式省略号的可变参数以任何方式都不携带类型信息。这就是为什么像
printf()
这样的东西使用格式说明符的原因,因为它需要一种方法来知道将东西转换成什么


当你可以使用C++ 11时,你应该使用可变模板,这样就可以制作任何类型的助手,就像你的AgReWrPad一样。

< P>当你有一个C++编译器支持C++ 11的初始化列表特性时,你可以把PrPARTGS函数写为

#include <initializer_list>

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

这有时比可变模板更容易。

< P>当你有一个C++编译器支持C++ 11的初始化列表特性时,你可以把PrPARTGS函数写为

#include <initializer_list>

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

有时,这可能比可变模板更简单。

可变模板的救援:

template <typename ...Args>
R call(int n, Args &&... args)
{
    return printArgs(n, ArgWrapper(std::forward<Args>(args))...);
}
模板
R调用(int n,Args&…Args)
{
返回printArgs(n,ArgWrapper(std::forward(args))…);
}

这是假设您的
printArgs
函数必须实际使用C型变量。有赞成和反对的理由;如果一切都是C++,你有几个选择。

救援模板:

template <typename ...Args>
R call(int n, Args &&... args)
{
    return printArgs(n, ArgWrapper(std::forward<Args>(args))...);
}
模板
R调用(int n,Args&…Args)
{
返回printArgs(n,ArgWrapper(std::forward(args))…);
}
这是假设您的
printArgs
函数必须实际使用C型变量。有赞成和反对的理由;如果一切都是C++,你有几个选择。
template <typename ...Args>
R call(int n, Args &&... args)
{
    return printArgs(n, ArgWrapper(std::forward<Args>(args))...);
}