473,396 Members | 1,804 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,396 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 4194
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...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development projectplanning, coding, testing,...

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.