Template Magic to create variable length arguments to a function?

C

Clay_Culver

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...
 
C

Clay_Culver

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.
 
P

peter steiner

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
 
M

mlimber

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...90b30/5fbecab933500acc?hl=en#5fbecab933500acc

Cheers! --M
 
C

Clay_Culver

Doh! Why didn't I think of that? That linked post seems to be the
easiest solution, thanks.
 
N

n2xssvv g02gfr12930

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
 
P

peter steiner

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
 
J

John Harrison

peter said:
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
 
G

Greg

peter said:
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
 
G

Greg

peter said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top