How can I get a variable amount of arguments in a function without providing how many arguments will be passed?

For example, when you use a VA List, the first parameter must be the amount of arguments passed.. I don't want that. I want to just start passing any amount of arguments to the function.

Is there a way to do this? I've heard that the boost library supports this.. Whether or not that is true, I don't know but I don't "want" to use boost. Though I may have to if the above statement is true and there is no other way.

So again, can I do this? And if not, why?

Recommended Answers

All 6 Replies

Well, without any special additions, you have two options:
1:First argument passed is the number of arguments.
2:Last argument passed is to indicate that it is the last one, and you should stop getting arguments.

Other than that, you could pass some collection of objects (assuming all of the same type).

It would be helpful if you could explain what you're trying to accomplish by doing this.

There are a few possibilities:

The ugly way: Use variadic functions from C. This is what you were referring to with the "va_list". You should know that the first argument does not have to be the count of arguments, it could be anything, but C variadic functions don't give you any other means to know how many parameters were passed, so you need to figure out some way to infer that (e.g. the printf() functions infer it from parsing the formatted string). This method is ugly because it is not type-safe, and it has limited application.

The new way: Use variadic templates from C++11 (the new standard). The new C++ standard has introduced a new feature called variadic templates which allow for variable number of parameters to function templates (where each parameter's type is templated too). This is both type-safe and will tell you how many parameters have been passed. Of course, you have to do a bit of template wizardry to write the function (and its overloads for different specific parameters).

The traditional way: Use default parameter values. Basically, this allows for variable numbers of parameters, but the sequence is fixed, and has an upper-bound, of course. For most cases, this is sufficient.

The Boost way: Use the Boost.Parameter library. This library is designed to make "packs" with the parameters of the function, allowing any ordering, naming them explicitly at the call-site, and default values, of course. This is pretty much as flexible as it gets. But if you don't "want" to use Boost, then so be it, you might still want to take a look at how they accomplish that.

The good way: Use the well-known named-parameter idiom. This simply means that you wrap your function inside a callable object (functor) and that you provide a certain number of member functions to set certain parameters. Each "set" function returns a reference it the "this" object, meaning that the "set" calls can be chained. Also, you can easily return another object from the "set" function and thus creating a branching in the parameter-list. I have used this idiom in the past and it works like magic. And because the callable object is usually temporary and created on the stack, at the call-site, it really boils down to the same thing as a function call, with little overhead.

The designed way: Use polymorphic types as arguments (using either static or dynamic polymorphism). Generally, if you have a function that could take many parameters (and any number of them), it usually means that you have a certain number of different ways in which the function could do its work. If that is the case, these different ways in which the function could morph into should probably be encapsulated into some polymorphic objects of some kind.


Personally, I find Boost.Parameter a bit too verbose, I generally prefer the other recommended methods: default parameters do just fine in most simple situations; variadic templates are great for parameter forwarding and printf-like functions; the named-parameter idiom works wonders for things like configuring an algorithm with a bunch of parameters before executing it; and, polymorphism is generally preferred when you are really dealing with different variants of an algorithm as opposed to just optional parameters.

I'm trying the templates but still don't get it:

//Does not work:
    template<typename... Values>
    void foo(const Values&... values)
    {

    }
//Works:
template <typename ...Args> class SomeStruct {
    void Foo(Args...);
};

An easy way to use variadic template functions is with direct recursion:

#include <iostream>

using namespace std;

void foo()
{
    // Base case for variadic recursion
}

template<typename T, typename... Args>
void foo(T first, const Args... remaining)
{
    // Use the first argument
    cout << first << endl;
    
    // Recursively pass on the remaining arguments
    foo(remaining...);
}

int main()
{
    cout.setf(ios::boolalpha); // To make bool args print right
    
    foo(1, "test", 3.14159, 'Q', true, 6);
}
commented: Doesn't work but thanks anyway Rep+1 +6

An easy way to use variadic template functions is with direct recursion:

#include <iostream>

using namespace std;

void foo()
{
    // Base case for variadic recursion
}

template<typename T, typename... Args>
void foo(T first, const Args... remaining)
{
    // Use the first argument
    cout << first << endl;
    
    // Recursively pass on the remaining arguments
    foo(remaining...);
}

int main()
{
    cout.setf(ios::boolalpha); // To make bool args print right
    
    foo(1, "test", 3.14159, 'Q', true, 6);
}

Hey I figured it out.. I had to set compiler flags for codeblocks.. but for visual studio, it won't work.

THANX! Your the best :)


Edit:

Oops meant to PM that.

Visual Studio doesn't support variadic templates yet.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.