# How to pass multiple parameters - unknown number/type at compile time?

This topic is 4903 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Not sure exactly how to word this, but what's the best method of passing parameters to a function in C++, when you don't know the number or type of parameters at compile time? Is this possible? The type includes class instances as well as integers, characters, floats etc. Thanks

##### Share on other sites
Use va_lists as such: (taken from msdn examples)

/* The program below illustrates passing a variable * number of arguments using the following macros: *      va_start            va_arg              va_end *      va_list             va_dcl (UNIX only) */#include <stdio.h>#define ANSI            /* Comment out for UNIX version     */#ifdef ANSI             /* ANSI compatible version          */#include <stdarg.h>int average( int first, ... );#else                   /* UNIX compatible version          */#include <varargs.h>int average( va_list );#endifint main( void ){   /* Call with 3 integers (-1 is used as terminator). */   printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );   /* Call with 4 integers. */   printf( "Average is: %d\n", average( 5, 7, 9, 11, -1 ) );   /* Call with just -1 terminator. */   printf( "Average is: %d\n", average( -1 ) );}/* Returns the average of a variable list of integers. */#ifdef ANSI             /* ANSI compatible version    */int average( int first, ... ){   int count = 0, sum = 0, i = first;   va_list marker;   va_start( marker, first );     /* Initialize variable arguments. */   while( i != -1 )   {      sum += i;      count++;      i = va_arg( marker, int);   }   va_end( marker );              /* Reset variable arguments.      */   return( sum ? (sum / count) : 0 );}#else       /* UNIX compatible version must use old-style definition.  */int average( va_alist )va_dcl{   int i, count, sum;   va_list marker;   va_start( marker );            /* Initialize variable arguments. */   for( sum = count = 0; (i = va_arg( marker, int)) != -1; count++ )      sum += i;   va_end( marker );              /* Reset variable arguments.      */   return( sum ? (sum / count) : 0 );}#endif

##### Share on other sites
My best bet would be the ... "parameter".
It's actually called a variable argument list.

But I don't really like it...
It's used in the printf kind of functions (among others).
Though I prefer the std::cout operator <<, but that's just me.

To come back to your original question.
Look at this site:
http://www.cprogramming.com/tutorial/lesson17.html

It explains a bit of the variable arguments list.

##### Share on other sites
I think this is only good for POD types (int, char etc)? I'm also interested in passing objects around.

Thanks

##### Share on other sites
Yes, variable argument lists only work for builtin types. Not to mention that:
Quote:
 Original quote from SiCrane, immortalised in Zahlman's sig:"Basically whenever you invoke the dread ellipses construct you leave the happy world of type safety."

If you really want to do this google for discriminated unions (aka. variants) or look at boost::variant, boost::many and/or boost::any. However, it may be that there's a simpler/better way of doing what you want to do, such as templates or operator chaining (like how c++ streams work). What exactly is it you're wanting to do?

Enigma

##### Share on other sites
Operator chaining for the win!!!

Example from my latest "drawing board" workspace (think of it as a sketchpad for sourcecode):

	graphics::scene_type scene;	scene.insert		( graphics::square   ( range(-100.0,+100.0) , range(-100.0,+100.0) ) )		( graphics::triangle ( range(-100.0,+100.0) , range(-100.0,+100.0) ) )		;

How'd I get this to compile? That's simple, insert() returns an object which has a function named operator(). For example, if I wanted the above to simply recall insert() for every extra "argument", I could do something similar to this:

namespace graphics {	class scene_type;	class scene_inserter {		scene_type & scene;	public:		scene_inserter( scene_type & scene )			: scene( scene )		{		}		template < typename type >		scene_inserter & operator()( type );	};		class scene_type : public renderable_type {		...	public:		template < typename type >		scene_inserter insert( type object );	};	template < typename type >	scene_inserter & scene_inserter::operator()( type object ) {		scene.insert( object );		return *this;	}	template < typename type >	scene_inserter scene_type::insert( type object ) {		//implement the adding of the object into an internal list or similar		return scene_inserter( *this );	}}

##### Share on other sites
You may want to look like the source code for various scriptining languages. Some of them support calls to arbitrary C++ functions. In particular, I believe AngelCode, produced by one of our affiliates, supports calls that include C++ objects.

##### Share on other sites
I don't understand the operator chaining!

Basically I have a ScriptManager that has a function named Call. It is invoked by C++. Call looks like this at the moment:

void Call(const char* name, const char* args, ...);

Call essentially invokes the Lua function name, and passes it the arguments from the va_list. I want it to be a generic Call function, hence my question.

I'm using ToLua++ for creating C++ bindings for Lua, but I'll see if Boost will solve my problem.

##### Share on other sites
Vectors need to know the types at compile time I think.

##### Share on other sites
Quote:
 Original post by stodgeI don't understand the operator chaining!

Okay, a more explanitory example then :-).

Basically, operator chaining is where you use operators to make it more obvious things are on the same level.

If we were to implement a function called "Add" without variable arguments, we'd have to call it multiple times to add numbers together:
Add( Add( Add( 3 , 4 ) , 5 ) , 6 )

Obviously, using operator+ makes this clearer:
3 + 4 + 5 + 6

Now with C++ you can overload operators yourself, as long as we get things started with a custom type - you can't overload (3 + 4) to evaluate to anything but 7.

iostreams use operator chaining, for example:
std::cout << 3 << 4;

This is clearer than: Print( Print( std::cout , 3 ) , 4 )

However, that's basically what's happening on the inside.

In this case, std::cout is of the type std::ostream, so there's some code somewhere that looks somewhat like this:
std::ostream & operator<<( std::ostream & os , int number ) {    //print number using the stream os    return os;}

Then, the compiler internally translates this:
std::cout << 3 << 4;

Into:
operator<<( operator<<( std::cout , 3 ) , 4 );

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 29
• 16
• 11
• 10
• 11
• ### Forum Statistics

• Total Topics
634112
• Total Posts
3015584
×