I had a really cool idea today, but I can't get it to work.
I'm trying to make a class similar to va_list, but it stores the number of variable arguments passed. That way, you don't have to have an extra parameter to tell you how many arguments there are. To do this, I planned on overloading the "," operator to push back arguments of any type onto a queue. Functions would be declared/called like this:
1 2 3
type foo(vparam bar=vparam());
//...
foo(46,12,0,384);
However, this all requires one very crucial thing to be valid: I must be able to pass a value of arbitrary type instead of the variable parameter type, which would be passed to the constructor. If this doesn't work, the first value of the variable parameter type wouldn't be passed as a vparam, and a "," overload wouldn't work. While this seems to work for non-templated functions, templated functions say "foo(type) was not declared in this scope"
Does anyone know how to do this, or if it's even possible? Otherwise, it could get cumbersome...
It's funny, because I actually tried making it contain any containers when I was experimenting with it. So, it needs parenthesis around it? That really sucks... Oh well, I guess this idea is a bust.
Either way it does. The second way because we use the varargs constructor. The first way because the
compiler isn't smart enough to realize that in the expression
func( a, b, c, d )
a is mapped to the first parameter of func whereas a varargs should be implicitly constructed from b so that
all subsequent parameters can be stuffed into the varargs via the , operator.
I guess you may know this, but I have to mention - C++0x will have variadic templates. This will probably work much better for a general packing/unpacking routine and also for a stub function in front of the actual call. Template code bloat is the only remaining concern. For the time being I kind-of like the above solutions. The world is not perfect.
EDIT: Forgot to mention initializer lists. They will allow you to write stuff like max({1, 2, 3}). The arguments must be of the same type, but it is nice for functions that process sets of stuff.
Yes, variadic templates eliminates the gazillion constructors and the arbitrary limitation on the number of arguments supported, but it doesn't solve the underlying problem in that use of varargs requires extra syntax at the call point. But the worst part about these solutions, in my opinion, is the fact that I have to know the types of the arguments in order to extract them from the object. I suppose this would be OK for a typesafe C++ version of printf, but to pass anything other than compiler intrinsic types (PODs) through a varargs object would require func() to be modified to know of the additional types, which is, in itself fairly limiting.
One way around that problem would be to use boost::variant instead of boost::any as the argument holder. However, the actual variant type would need to be constructed from the callpoint, otherwise variant itself has a limited number template parameters, and this would be overly restrictive to the user. Then, func() would need to use static_visitor objects to access the parameters in a typesafe way, which would lead to a completely different design of func(). It would be an interesting exercise nonetheless.
I understand you have given this some thought. I'm not going to pretend that I am well versed for boost conversation, but apparently the variant mechanism is a bit irky in the grand scheme of things in order to make it robust. It would be nice to have type-safe hierarchy-independent robust polymorphic processing, to which I can not see even the conceptual solution. Alas, I am used to the static approach to things.