I’m working on something that allows me to make it easier to call functions in a scripting language (Lua) and one idea was to use variadic arguments. There are two ways to do that:
Call( int count, ... )
and
Call( const char* args, ... )
like printf. I thought the first one would be a little easier to maintain, so I tried doing it by making a wrapper to manage types of arguments. It looks like this:
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;
};
This works fine and dandy, but when I actually try to make this work in a varadic arguments construction, it turns out that the values aren’t actually casted.
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 );
The above results in garbage, while this works perfectly fine:
printArgs( 4, (ArgWrapper)1337.0f, (ArgWrapper)18, (ArgWrapper)37.0, (ArgWrapper)true );
How do I specify that each variadic argument should have the same common type?
When you use C++03, you can’t, since variadic arguments using the c-style ellipsis
...do not carry type information in any way. This is why stuff likeprintf()uses format specifiers, since it needs a way to know what to cast stuff to.When you can use C++11, you should use variadic templates right away which would make any kind of helper like your ArgWrapper unnecessary.