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? 13 4031
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.
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.
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 :)
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
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.
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);
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.
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
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;
}
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.
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
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?
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 This discussion thread is closed Replies have been disabled for this discussion. Similar topics
21 posts
views
Thread by Batista, Facundo |
last post: by
|
6 posts
views
Thread by S.Tobias |
last post: by
|
reply
views
Thread by Chris Fink |
last post: by
|
1 post
views
Thread by Rob Griffiths |
last post: by
|
669 posts
views
Thread by Xah Lee |
last post: by
|
3 posts
views
Thread by john |
last post: by
|
7 posts
views
Thread by Sky |
last post: by
|
9 posts
views
Thread by weirdwoolly |
last post: by
|
5 posts
views
Thread by JH |
last post: by
| | | | | | | | | | | |