我正在开发一些能让我更容易用脚本语言(Lua)调用函数的东西,其中一个想法是使用可变参数。有两种方法可以做到这一点:
Call( int count, ... )
和
Call( const char* args, ... )
像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 );
以上结果是垃圾,而这完全正常:
printArgs( 4, (ArgWrapper)1337.0f, (ArgWrapper)18, (ArgWrapper)37.0, (ArgWrapper)true );
如何指定每个可变参数应具有相同的公共类型?
答案 0 :(得分:4)
当您使用C ++ 03时,您不能,因为使用c样式省略号...
的可变参数不以任何方式携带类型信息。这就是像printf()
之类的东西使用格式说明符的原因,因为它需要一种方法来知道要将内容转换为什么。
当您可以使用C ++ 11时,您应该立即使用可变参数模板,这样就不需要像ArgWrapper那样的任何类型的帮助。
答案 1 :(得分:0)
如果你有一个支持C ++ 11初始化列表功能的C ++编译器,你可以将printArgs函数编写为
#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({ 4, 1337.0f, 18, 37.0, true });
这有时可能比可变参数模板更容易。
答案 2 :(得分:0)
拯救的可变参数模板:
template <typename ...Args>
R call(int n, Args &&... args)
{
return printArgs(n, ArgWrapper(std::forward<Args>(args))...);
}
这假设你的printArgs
函数必须实际使用C风格的可变参数。有理由支持和反对它;如果一切都是C ++,你有几个选择。