473,221 Members | 1,906 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,221 software developers and data experts.

type-safe varargs

Goal: to provide the simplest call-site possible at the cost of
upfront hackery.

I have a function that essentially takes a variable list of arguments:

func(const string &k0, unsigned long long v0, const string &k1,
unsigned long long v1, etc)

This is going to be called a LOT from code that is hand-written, so I
really ant to simplify the job of calling this function.

Options I have found:

Use varargs.
func(...)
This has the plus of being simple and unlimited. It has the downside
of being limited to built-in types - char * rather than string. It
also has the downside of forcing the caller to make sure literal ints
are ULL, lest we unbalance the stack.
Use C pre-processor hackery to get __VA_ARGS__ to initialize an array
arg.
#define FUNC(...) FUNC_((kvpair[]){__VA_ARGS__, {NULL}})
This falls down as soon as you use anything but a literal in the
call. And the syntax confuses every syntax coloring app I have
seen :)
Use default args.
func(const string &k0, unsigned long long v0,
const string &k1="", unsigned long long v1=0,
const string &k2="", unsigned long long v2=0,
const string &k3="", unsigned long long v3=0,
const string &k4="", unsigned long long v4=0)
This has the upside that it is type-safe and simple to call. It has
the downside that I need to extend the args list to cover the worst
case caller, and pay that cost at every call.
Can anyone suggest a better design?
Dec 20 '07 #1
13 4184
On Dec 20, 6:38 am, Tim H <thoc...@gmail.comwrote:
Goal: to provide the simplest call-site possible at the cost of
upfront hackery.

I have a function that essentially takes a variable list of arguments:

func(const string &k0, unsigned long long v0, const string &k1,
unsigned long long v1, etc)

This is going to be called a LOT from code that is hand-written, so I
really ant to simplify the job of calling this function.

Options I have found:

Use varargs.
func(...)
This has the plus of being simple and unlimited. It has the downside
of being limited to built-in types - char * rather than string. It
also has the downside of forcing the caller to make sure literal ints
are ULL, lest we unbalance the stack.

Use C pre-processor hackery to get __VA_ARGS__ to initialize an array
arg.
#define FUNC(...) FUNC_((kvpair[]){__VA_ARGS__, {NULL}})
This falls down as soon as you use anything but a literal in the
call. And the syntax confuses every syntax coloring app I have
seen :)

Use default args.
func(const string &k0, unsigned long long v0,
const string &k1="", unsigned long long v1=0,
const string &k2="", unsigned long long v2=0,
const string &k3="", unsigned long long v3=0,
const string &k4="", unsigned long long v4=0)
This has the upside that it is type-safe and simple to call. It has
the downside that I need to extend the args list to cover the worst
case caller, and pay that cost at every call.

Can anyone suggest a better design?
How about an object to encapsulate all the parameters.

Something like (foreshortened example):
struct Params {
string& k1;
string& k2;
ull v1;
ull v2;
Params(const string& k1, const string&k2) : k1(k1), k2(k2), v1(0),
v2(0) {}
Params(const string& k1, ull v1) : k1(k1), v1(v1), v2(0) {}
Params(const string& k1, ull v1, ull v2) : k1(k1), v1(v1), v2(v2) {}
// etc - only need to cover the permutations you use
};

then.

extern void func(const Params&);
:
func(Params("foo", "bar"));
func(Params("baz", 123345ULL));
func(Params("yadda", 123344ULL, 789010ULL));

etc.

Dec 20 '07 #2
On Dec 20, 11:19 am, tragomaskhalos <dave.du.verg...@logicacmg.com>
wrote:
>
Something like (foreshortened example):
struct Params {
string& k1;
string& k2;
Oops. Should be
const string& k1;
const string& k2;
I think this is OK wrt binding-to-temporary lifetime issues,
hopefully someone will shoot me down if not.
Dec 20 '07 #3
On Dec 20, 3:41 am, tragomaskhalos <dave.du.verg...@logicacmg.com>
wrote:
On Dec 20, 11:19 am, tragomaskhalos <dave.du.verg...@logicacmg.com>
wrote:
Something like (foreshortened example):
struct Params {
string& k1;
string& k2;

Oops. Should be
const string& k1;
const string& k2;
I think this is OK wrt binding-to-temporary lifetime issues,
hopefully someone will shoot me down if not.
I still need to provide a constructor that has 32 pairs of (kn, vn) or
32 different constructors. At least with 32 different ctors, I don't
pay the perf cost. It's still hideous :)
Dec 20 '07 #4
On 2007-12-20 01:38:44 -0500, Tim H <th*****@gmail.comsaid:
Goal: to provide the simplest call-site possible at the cost of
upfront hackery.

I have a function that essentially takes a variable list of arguments:

func(const string &k0, unsigned long long v0, const string &k1,
unsigned long long v1, etc)

This is going to be called a LOT from code that is hand-written, so I
really ant to simplify the job of calling this function.

Options I have found:

Use varargs.
func(...)
This has the plus of being simple and unlimited. It has the downside
of being limited to built-in types - char * rather than string. It
also has the downside of forcing the caller to make sure literal ints
are ULL, lest we unbalance the stack.
Use C pre-processor hackery to get __VA_ARGS__ to initialize an array
arg.
#define FUNC(...) FUNC_((kvpair[]){__VA_ARGS__, {NULL}})
This falls down as soon as you use anything but a literal in the
call. And the syntax confuses every syntax coloring app I have
seen :)
Use default args.
func(const string &k0, unsigned long long v0,
const string &k1="", unsigned long long v1=0,
const string &k2="", unsigned long long v2=0,
const string &k3="", unsigned long long v3=0,
const string &k4="", unsigned long long v4=0)
This has the upside that it is type-safe and simple to call. It has
the downside that I need to extend the args list to cover the worst
case caller, and pay that cost at every call.
Can anyone suggest a better design?
How about defining the function as an object instead?

class func
{
public:
func &set(const string &key, unsigned long long val)
{
// do whatever you need with the parameter here.
return *this;
}

int execute()
{
// this is the actual "function" call here.
}
};

This code will support syntax like
func.set("foo", 1).set("bar", 2).execute();

Furthermore, if the keys for the parameters are known at compile time,
you can make it more efficient by declaring methods like
func &setFoo(unsigned long long val);
to make runtime more efficient.

--

-kira

Dec 20 '07 #5
On Dec 19, 10:38 pm, Tim H <thoc...@gmail.comwrote:
Goal: to provide the simplest call-site possible at the cost of
upfront hackery.

I have a function that essentially takes a variable list of arguments:

func(const string &k0, unsigned long long v0, const string &k1,
unsigned long long v1, etc)

This is going to be called a LOT from code that is hand-written, so I
really ant to simplify the job of calling this function.

Options I have found:

Use varargs.
func(...)
This has the plus of being simple and unlimited. It has the downside
of being limited to built-in types - char * rather than string. It
also has the downside of forcing the caller to make sure literal ints
are ULL, lest we unbalance the stack.

Use C pre-processor hackery to get __VA_ARGS__ to initialize an array
arg.
#define FUNC(...) FUNC_((kvpair[]){__VA_ARGS__, {NULL}})
This falls down as soon as you use anything but a literal in the
call. And the syntax confuses every syntax coloring app I have
seen :)

Use default args.
func(const string &k0, unsigned long long v0,
const string &k1="", unsigned long long v1=0,
const string &k2="", unsigned long long v2=0,
const string &k3="", unsigned long long v3=0,
const string &k4="", unsigned long long v4=0)
This has the upside that it is type-safe and simple to call. It has
the downside that I need to extend the args list to cover the worst
case caller, and pay that cost at every call.

Can anyone suggest a better design?

void func(const std::vector<boost::any&);

or if you want to change the arguments:
void func(std::vector<boost::any&);

upside is that boost::any can encapsulate anything with a copy
constructor including POD types.
You could write simple functions for any possible argument combination
which return a vector, e.g.
std::vector<boost::anycreateVectorByStringAndInt(c onst std::string
&_r0, const int _i1)
{ std::vector<boost::anys;

s.push_back(_r0);
s.push_back(_i1);
return s;
}

then you could do
std::string s0;
int i1;
func(createVectorByStringAndInt(s0, i1));

Be aware that using boost::any is not free.
When creating a boost::any an object is allocated on the heap and the
passed object is copy-constructed.
Same for copying boost::any.
Dec 21 '07 #6
On Dec 19, 10:38 pm, Tim H <thoc...@gmail.comwrote:
Goal: to provide the simplest call-site possible at the cost of
upfront hackery.

I have a function that essentially takes a variable list of arguments:

func(const string &k0, unsigned long long v0, const string &k1,
unsigned long long v1, etc)

This is going to be called a LOT from code that is hand-written, so I
really ant to simplify the job of calling this function.

Options I have found:

Use varargs.
func(...)
This has the plus of being simple and unlimited. It has the downside
of being limited to built-in types - char * rather than string. It
also has the downside of forcing the caller to make sure literal ints
are ULL, lest we unbalance the stack.

Use C pre-processor hackery to get __VA_ARGS__ to initialize an array
arg.
#define FUNC(...) FUNC_((kvpair[]){__VA_ARGS__, {NULL}})
This falls down as soon as you use anything but a literal in the
call. And the syntax confuses every syntax coloring app I have
seen :)

Use default args.
func(const string &k0, unsigned long long v0,
const string &k1="", unsigned long long v1=0,
const string &k2="", unsigned long long v2=0,
const string &k3="", unsigned long long v3=0,
const string &k4="", unsigned long long v4=0)
This has the upside that it is type-safe and simple to call. It has
the downside that I need to extend the args list to cover the worst
case caller, and pay that cost at every call.

Can anyone suggest a better design?
func(const std::vector<std::pair<std::string, unsigned long long
&_r);
Dec 21 '07 #7
On Dec 20, 4:14 pm, Peter <ExcessPh...@gmail.comwrote:
On Dec 19, 10:38 pm, Tim H <thoc...@gmail.comwrote:
Goal: to provide the simplest call-site possible at the cost of
upfront hackery.
I have a function that essentially takes a variable list of arguments:
func(const string &k0, unsigned long long v0, const string &k1,
unsigned long long v1, etc)
This is going to be called a LOT from code that is hand-written, so I
really ant to simplify the job of calling this function.
Options I have found:
Use varargs.
func(...)
This has the plus of being simple and unlimited. It has the downside
of being limited to built-in types - char * rather than string. It
also has the downside of forcing the caller to make sure literal ints
are ULL, lest we unbalance the stack.
Use C pre-processor hackery to get __VA_ARGS__ to initialize an array
arg.
#define FUNC(...) FUNC_((kvpair[]){__VA_ARGS__, {NULL}})
This falls down as soon as you use anything but a literal in the
call. And the syntax confuses every syntax coloring app I have
seen :)
Use default args.
func(const string &k0, unsigned long long v0,
const string &k1="", unsigned long long v1=0,
const string &k2="", unsigned long long v2=0,
const string &k3="", unsigned long long v3=0,
const string &k4="", unsigned long long v4=0)
This has the upside that it is type-safe and simple to call. It has
the downside that I need to extend the args list to cover the worst
case caller, and pay that cost at every call.
Can anyone suggest a better design?

func(const std::vector<std::pair<std::string, unsigned long long
&_r);
And how does the caller call that? You can't declare a vector the
same way you can an array.

I want to see the call-site be something like:
func("key1", 1, "key2", 2, "key3, 99, "key4", -12345678);

I know it sounds silly, but trust me, it makes my life a whole lot
easier, the simpler it is.
Dec 21 '07 #8
Tim H wrote:
On Dec 20, 4:14 pm, Peter <ExcessPh...@gmail.comwrote:
>On Dec 19, 10:38 pm, Tim H <thoc...@gmail.comwrote:
>>Goal: to provide the simplest call-site possible at the cost of
upfront hackery.
>>I have a function that essentially takes a variable list of
arguments:
>> func(const string &k0, unsigned long long v0, const string &k1,
unsigned long long v1, etc)
>>This is going to be called a LOT from code that is hand-written, so
I really ant to simplify the job of calling this function.
>>Options I have found:
>>Use varargs.
func(...)
This has the plus of being simple and unlimited. It has the
downside of being limited to built-in types - char * rather than
string. It also has the downside of forcing the caller to make
sure literal ints are ULL, lest we unbalance the stack.
>>Use C pre-processor hackery to get __VA_ARGS__ to initialize an
array arg.
#define FUNC(...) FUNC_((kvpair[]){__VA_ARGS__, {NULL}})
This falls down as soon as you use anything but a literal in the
call. And the syntax confuses every syntax coloring app I have
seen :)
>>Use default args.
func(const string &k0, unsigned long long v0,
const string &k1="", unsigned long long v1=0,
const string &k2="", unsigned long long v2=0,
const string &k3="", unsigned long long v3=0,
const string &k4="", unsigned long long v4=0)
This has the upside that it is type-safe and simple to call. It has
the downside that I need to extend the args list to cover the worst
case caller, and pay that cost at every call.
>>Can anyone suggest a better design?

func(const std::vector<std::pair<std::string, unsigned long long
&_r);

And how does the caller call that? You can't declare a vector the
same way you can an array.

I want to see the call-site be something like:
func("key1", 1, "key2", 2, "key3, 99, "key4", -12345678);

I know it sounds silly, but trust me, it makes my life a whole lot
easier, the simpler it is.
But varargs is not simple is it?

--
Jim Langston
ta*******@rocketmail.com
Dec 21 '07 #9
Dredging up an old thread with a new answer. I wish I was less proud
of this. Is __VA_ARGS__ standard C++ or just C99?

#include <vector>
#include <iostream>

// do whatever you need in your helper
struct helper
{
public:
helper(const std::string &str): m_str(str)
{
}
const std::string &
str() const
{
return m_str;
}

private:
std::string m_str;
};

typedef std::vector<helperhelper_list;

inline helper_list
operator,(const helper &lhs, const helper &rhs)
{
helper_list tmp;
tmp.push_back(lhs);
tmp.push_back(rhs);
return tmp;
}
inline helper_list
operator,(const helper_list &lhs, const helper &rhs)
{
helper_list tmp(lhs);
tmp.push_back(rhs);
return tmp;
}

/*
* unlimited_args()
*
* It can take an "unlimited" number of arguments, in the form:
* unlimited_args((helper("abc"), helper("def")))
*
* NOTE: In calling this, the extra parens are required. Why?
* Well, C++ won't call operator,() on function arguments, so we force
* the arguments to be a single argument, which is an expression.
* Fortunately, a touch of macro magic makes it look like an unlimited
* argument list.
*/
#define unlimited_args(name, ...) unlimited_args_impl(name,
(__VA_ARGS__))

void
unlimited_args_impl(const std::string &name, const helper_list &args)
{
std::cout << name << std::endl;
for (std::size_t i = 0; i < args.size(); i++) {
std::cout << " " << args[i].str() << std::endl;
}
}
// With a smarter custom helper_list (less than 30 LOC), this overload
can be
// avoided.
void
unlimited_args_impl(const std::string &name, const helper &arg)
{
helper_list hl;
hl.push_back(arg);
unlimited_args_impl(name, hl);
}

int
main()
{
// these calls can take any number of helper args
unlimited_args("small", helper("a"));
unlimited_args("medium", helper("a"), helper("b"));
unlimited_args("large", helper("a"), helper("b"),
helper("c"));

return 0;
}

Jan 18 '08 #10
Tim H wrote:
Dredging up an old thread with a new answer. I wish I was less proud
of this. Is __VA_ARGS__ standard C++ or just C99?
Variadic macros are C99 (not sure of the exact C99 syntax), and I
believe they're slated for C++0x. However, the current (C++03)
preprocessor does not support variadic macros.
Jan 18 '08 #11
On Jan 18, 8:11 am, red floyd <no.s...@here.dudewrote:
Tim H wrote:
Dredging up an old thread with a new answer. I wish I was less proud
of this. Is __VA_ARGS__ standard C++ or just C99?

Variadic macros are C99 (not sure of the exact C99 syntax), and I
believe they're slated for C++0x. However, the current (C++03)
preprocessor does not support variadic macros.
I compiled the above code on gcc, so no surprise. Even so, the
calling syntax could change to:

unlimited_args("foo" (helper("a"), helper("b"), helper("c"));

Tim
Jan 18 '08 #12
Tim H wrote:
On Jan 18, 8:11 am, red floyd <no.s...@here.dudewrote:
>Tim H wrote:
Dredging up an old thread with a new answer. I wish I was less proud
of this. Is __VA_ARGS__ standard C++ or just C99?

Variadic macros are C99 (not sure of the exact C99 syntax), and I
believe they're slated for C++0x. However, the current (C++03)
preprocessor does not support variadic macros.

I compiled the above code on gcc, so no surprise.
In standard C++ mode or in GNU C++ mode?

Jan 20 '08 #13
On Jan 20, 1:52 am, Rolf Magnus <ramag...@t-online.dewrote:
Tim H wrote:
On Jan 18, 8:11 am, red floyd <no.s...@here.dudewrote:
Tim H wrote:
Dredging up an old thread with a new answer. I wish I was less proud
of this. Is __VA_ARGS__ standard C++ or just C99?
Variadic macros are C99 (not sure of the exact C99 syntax), and I
believe they're slated for C++0x. However, the current (C++03)
preprocessor does not support variadic macros.
I compiled the above code on gcc, so no surprise.

In standard C++ mode or in GNU C++ mode?
I did not specify any g++ options except -Wall
Jan 20 '08 #14

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

21
by: Batista, Facundo | last post by:
Here I send it. Suggestions and all kinds of recomendations are more than welcomed. If it all goes ok, it'll be a PEP when I finish writing/modifying the code. Thank you. .. Facundo
6
by: S.Tobias | last post by:
I'm trying to understand how structure type completion works. # A structure or union type of unknown # content (as described in 6.7.2.3) is an incomplete type. It # is ...
0
by: Chris Fink | last post by:
When I am consuming a webservice, an object has an undefined value (inq3Type.Call3Data). I do not completely understand why this is happening and apologize for the vague question. My assumption...
1
by: Rob Griffiths | last post by:
Can anyone explain to me the difference between an element type and a component type? In the java literature, arrays are said to have component types, whereas collections from the Collections...
669
by: Xah Lee | last post by:
in March, i posted a essay “What is Expressiveness in a Computer Language”, archived at: http://xahlee.org/perl-python/what_is_expresiveness.html I was informed then that there is a academic...
3
by: john | last post by:
Hi to All To demonstrate: public class MyBaseGenericClass<T> { } public class MyGenericClass1<T: MyBaseGenericClass<T> {
7
by: Sky | last post by:
I have been looking for a more powerful version of GetType(string) that will find the Type no matter what, and will work even if only supplied "{TypeName}", not the full "{TypeName},{AssemblyName}"...
9
by: weirdwoolly | last post by:
Hopefully someone will be able to help. I have written a stored procedure in C++ called from a Java test harness to validate the graphic data types in C++ and their use. I have declared the...
5
by: JH | last post by:
Hi I found that a type/class are both a subclass and a instance of base type "object". It conflicts to my understanding that: 1.) a type/class object is created from class statement 2.) a...
3
by: amanjsingh | last post by:
Hi, I am trying to implement Java Web Service using Apache Axis2 and Eclipse as a tool. I have created the basic code and deployed the service using various eclipse plugin but when I try to invoke...
1
isladogs
by: isladogs | last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, Mike...
0
by: veera ravala | last post by:
ServiceNow is a powerful cloud-based platform that offers a wide range of services to help organizations manage their workflows, operations, and IT services more efficiently. At its core, ServiceNow...
0
by: jianzs | last post by:
Introduction Cloud-native applications are conventionally identified as those designed and nurtured on cloud infrastructure. Such applications, rooted in cloud technologies, skillfully benefit from...
0
by: mar23 | last post by:
Here's the situation. I have a form called frmDiceInventory with subform called subfrmDice. The subform's control source is linked to a query called qryDiceInventory. I've been trying to pick up the...
0
by: abbasky | last post by:
### Vandf component communication method one: data sharing ​ Vandf components can achieve data exchange through data sharing, state sharing, events, and other methods. Vandf's data exchange method...
2
by: jimatqsi | last post by:
The boss wants the word "CONFIDENTIAL" overlaying certain reports. He wants it large, slanted across the page, on every page, very light gray, outlined letters, not block letters. I thought Word Art...
0
by: fareedcanada | last post by:
Hello I am trying to split number on their count. suppose i have 121314151617 (12cnt) then number should be split like 12,13,14,15,16,17 and if 11314151617 (11cnt) then should be split like...
0
Git
by: egorbl4 | last post by:
Скачал я git, хотел начать настройку, а там вылезло вот это Что это? Что мне с этим делать? ...
1
by: davi5007 | last post by:
Hi, Basically, I am trying to automate a field named TraceabilityNo into a web page from an access form. I've got the serial held in the variable strSearchString. How can I get this into the...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.