By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,385 Members | 1,737 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,385 IT Pros & Developers. It's quick & easy.

Template Magic to create variable length arguments to a function?

P: n/a
I have heard that it is possible to use classes + template magic to
make standalone functions (or maybe just a functor which acts like a
function) which can accept variable length arguments without using the
elipse. For example, a funciton could take in 1 known type, then a
variable list of other parameters:

ReturnValueClass rvc = someFunction("Some known type", 1, 0.2,
"string");
ReturnValueClass rvc2 = someFunction("Some known type again", true, 0);

This is without defining someFunction with the various different types
involved. Boost.Python does this with their "call" method which always
takes in a PyObject * as the first parameter, has a template for the
return value, and everything else after the first parameter is
magically accepted. This is example calling it:

int return1 = call<int>(somePyObject1, 'a', 1, true);
double return2 = call<double>(somePyObject2, 0.123, 4.2);
bool return 3 = call<bool>(somePyObject3);

Does anyone know where I can learn how to do this? I have started
digging through the Boost.Python source to learn, but that is a
veritable quagmire of templates, macros, and calls. It looks like it's
done by making the call "function" a class/struct, and the function
paramaters are made legal by templating+a macro expansion in the
template. Beyond that I'm having trouble figure out how to do this (my
use for this is very similar to what boost.python is doing, only with
something other than Python).

I'm not actually looking for someone to explain this complex topic here
on the group (though that would be great). I really just want to know
if anyone can link me to a minimal example/tutorial of how to do this
that I can build on for my own application

Thanks...

Nov 11 '05 #1
Share this Question
Share on Google+
10 Replies


P: n/a
Note I cannot use the elipse for this because I need to preserve the
type of the parameters. I'm planning on taking all of the parameters
passing each one into an object's constructor that's super-overloaded
to handle those types, and then putting each of those objects into an
std::list/vector so that I can manipulate them.

That's the idea anyway.

Nov 11 '05 #2

P: n/a
it is not possible to implement variable argument lists with templates.

the solution is to provide overloads for 1 to max arguments for your
specific function/functor.

e.g.

template <typename R, typename T1>
R x(T1 arg1);

template <typename R, typename T1, typename T2>
R x(T1 arg1, T2 arg2);

template <typename R, typename T1, typename T2, ..., typename TN>
R x(T1 arg1, T2 arg2, ..., TN argn);

you can use boost::preprocessor to programatically expand your
functions from a generic definition, this way you avoid a lot of
redundant code and possibly bugs. the macros that you see in
boost/python/call.hpp are an example of boost::preprocessor usage.

-- peter

Nov 11 '05 #3

P: n/a
Cl*********@yahoo.com wrote:
I have heard that it is possible to use classes + template magic to
make standalone functions (or maybe just a functor which acts like a
function) which can accept variable length arguments without using the
elipse. For example, a funciton could take in 1 known type, then a
variable list of other parameters:

ReturnValueClass rvc = someFunction("Some known type", 1, 0.2,
"string");
ReturnValueClass rvc2 = someFunction("Some known type again", true, 0);

This is without defining someFunction with the various different types
involved. Boost.Python does this with their "call" method which always
takes in a PyObject * as the first parameter, has a template for the
return value, and everything else after the first parameter is
magically accepted. This is example calling it:

int return1 = call<int>(somePyObject1, 'a', 1, true);
double return2 = call<double>(somePyObject2, 0.123, 4.2);
bool return 3 = call<bool>(somePyObject3);

Does anyone know where I can learn how to do this? I have started
digging through the Boost.Python source to learn, but that is a
veritable quagmire of templates, macros, and calls. It looks like it's
done by making the call "function" a class/struct, and the function
paramaters are made legal by templating+a macro expansion in the
template. Beyond that I'm having trouble figure out how to do this (my
use for this is very similar to what boost.python is doing, only with
something other than Python).

I'm not actually looking for someone to explain this complex topic here
on the group (though that would be great). I really just want to know
if anyone can link me to a minimal example/tutorial of how to do this
that I can build on for my own application

Thanks...


There are several options. See this post by Cy for an example of one:

http://groups.google.com/group/comp....becab933500acc

Cheers! --M

Nov 11 '05 #4

P: n/a
Ahhh I didn't realize this was using a special preprocessor. Thanks.

Nov 11 '05 #5

P: n/a
Doh! Why didn't I think of that? That linked post seems to be the
easiest solution, thanks.

Nov 11 '05 #6

P: n/a
Cl*********@yahoo.com wrote:
I have heard that it is possible to use classes + template magic to
make standalone functions (or maybe just a functor which acts like a
function) which can accept variable length arguments without using the
elipse. For example, a funciton could take in 1 known type, then a
variable list of other parameters:

ReturnValueClass rvc = someFunction("Some known type", 1, 0.2,
"string");
ReturnValueClass rvc2 = someFunction("Some known type again", true, 0);

This is without defining someFunction with the various different types
involved. Boost.Python does this with their "call" method which always
takes in a PyObject * as the first parameter, has a template for the
return value, and everything else after the first parameter is
magically accepted. This is example calling it:

int return1 = call<int>(somePyObject1, 'a', 1, true);
double return2 = call<double>(somePyObject2, 0.123, 4.2);
bool return 3 = call<bool>(somePyObject3);

Does anyone know where I can learn how to do this? I have started
digging through the Boost.Python source to learn, but that is a
veritable quagmire of templates, macros, and calls. It looks like it's
done by making the call "function" a class/struct, and the function
paramaters are made legal by templating+a macro expansion in the
template. Beyond that I'm having trouble figure out how to do this (my
use for this is very similar to what boost.python is doing, only with
something other than Python).

I'm not actually looking for someone to explain this complex topic here
on the group (though that would be great). I really just want to know
if anyone can link me to a minimal example/tutorial of how to do this
that I can build on for my own application

Thanks...

Clay,

C++ streams overload the >> and << operators enabling them to handle
different types. This technique enables multiple inputs and by creating
the << >> operators for your classes you create an easy mechanism for
input/output. It also happens to have the bonus of being more type safe.
In the example below the output of a string, integer, string, float and
line end are handled in that order as one combined operation.

int n = 6;
float f = 3.26;

std::cout << "integer = " << n << " , float = " << f << std::endl;

I'm sure you should be able to find examples of how to implement
the << >> operator overloads for classes.

Hope this helps

JFJB
Nov 11 '05 #7

P: n/a
Cl*********@yahoo.com wrote:
Ahhh I didn't realize this was using a special preprocessor. Thanks.


well, boost::preprocessor is not a special preprocessor but rather a
collection of magic preprocessor macros that allow you to do
"programming" on macro level, enabling things like the repetition i
showed above.

you can use this library on all halfway modern compilers without
external tools.

see http://www.boost.org/libs/preprocessor/doc/index.html

Nov 22 '05 #8

P: n/a
peter steiner wrote:
Cl*********@yahoo.com wrote:
Ahhh I didn't realize this was using a special preprocessor. Thanks.

well, boost::preprocessor is not a special preprocessor but rather a
collection of magic preprocessor macros that allow you to do
"programming" on macro level, enabling things like the repetition i
showed above.

you can use this library on all halfway modern compilers without
external tools.

see http://www.boost.org/libs/preprocessor/doc/index.html


I'd stongly recommend reading this first

http://boost-consulting.com/tmpbook/preprocessor.html

Until I read this I really didn't get the boost preprocessor, now I
think it's wonderful!

john
Nov 22 '05 #9

P: n/a
peter steiner wrote:
it is not possible to implement variable argument lists with templates.

the solution is to provide overloads for 1 to max arguments for your
specific function/functor.

e.g.

template <typename R, typename T1>
R x(T1 arg1);

template <typename R, typename T1, typename T2>
R x(T1 arg1, T2 arg2);

template <typename R, typename T1, typename T2, ..., typename TN>
R x(T1 arg1, T2 arg2, ..., TN argn);


It is possible to use std::tr1::tuple to represent a variable argument
list:

#include <tr1/tuple>
#include <iostream>

using std::tr1::tuple;

int main()
{
tuple<int, long, std::string> param_list(1, 2, "hello");

DoSomething( param_list );
...
}

and then implement DoSomething:

template <class Tuple>
void DoSomething( Tuple params )
{
int numParams = tuple_size<Tuple>::value;

std::cout << "number of args " << numParams << std::endl;

if ( --numParams < 0 ) return;

std::cout << "param 1" << get<0>(param_list);

if ( --numParams < 0 ) return;

std::cout << "param 2" << get<1>(param_list);

if ( --numParams < 0 ) return;

std::cout << "param 3" << get<2>(param_list);
}

Greg

Nov 22 '05 #10

P: n/a
peter steiner wrote:
it is not possible to implement variable argument lists with templates.

the solution is to provide overloads for 1 to max arguments for your
specific function/functor.

e.g.

template <typename R, typename T1>
R x(T1 arg1);

template <typename R, typename T1, typename T2>
R x(T1 arg1, T2 arg2);

template <typename R, typename T1, typename T2, ..., typename TN>
R x(T1 arg1, T2 arg2, ..., TN argn);

you can use boost::preprocessor to programatically expand your
functions from a generic definition, this way you avoid a lot of
redundant code and possibly bugs. the macros that you see in
boost/python/call.hpp are an example of boost::preprocessor usage.


It is possible to use std::tr1::tuple to pass a variable argument list
to a function:

#include <tr1/tuple>
#include <iostream>

using std::tr1::tuple;
using std::tr1::tuple_size;
using std::tr1::get;

// a function template accepting arbitrary parameter lists

template <class Tuple>
void DoSomething( Tuple params )
{
int numParams = tuple_size<Tuple>::value;

std::cout << "number of args: " << numParams << std::endl;

if ( --numParams < 0 ) return;

std::cout << "param 1: " << get<0>(params) << std::endl;

if ( --numParams < 0 ) return;

std::cout << "param 2: " << get<1>(params) << std::endl;

if ( --numParams < 0 ) return;

std::cout << "param 3: " << get<2>(params) << std::endl;
}

int main()
{
// let's call DoSomething() and pass it
// an int, a double and a std::string

tuple<int, double, std::string> params(1, -3.14159, "hello");

DoSomething( params );
}

Program Output:

param 1: 1
param 2: -3.14159
param 3: hello

Greg

Nov 22 '05 #11

This discussion thread is closed

Replies have been disabled for this discussion.