Jump to content
  • Advertisement
Sign in to follow this  
stodge

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

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

If you intended to correct an error in the post then please contact us.

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 this post


Link to post
Share on other sites
Advertisement
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 );
#endif

int 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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
Quote:
Original post by stodge
I 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 );

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!