3
votes

Is there some way to keep to use overloading with variable number of arguments?

Specific example is as follows:

// Third party class
class ABC
{
public:
    void addValue(int);
    void addValue(float);
    void addValue(string);
    void execute(); // Any number of add values can be called before the execute
};

Currently when I want to add values to the object of this class, I have to do as follows: ABC *obj = new ABC(); obj->addValue(2.0); obj->addValue("String"); obj->execute();

Is there some way that in the client code I can do all the addValues in 1 line?

I tried using macros as follow, but then I have to define a macro for every number of arguments:

#define ADD_1_VALUES_TO_CLASS_ABC(obj, val1) { \
    obj->addValue(val1) }
#define ADD_2_VALUES_TO_CLASS_ABC(obj, val1, val2) { \
    obj->addValue(val1); obj->addValue(val2) }
#define ADD_3_VALUES_TO_CLASS_ABC(obj, val1, val2, val3) { \
    obj->addValue(val1) ; obj->addValue(val2); obj->addValue(val3) }

Is there some generic way to define MACRO ADD_N_VALUES_TO_CLASS_ABC and call it like

ABC *obj = new ABC();
MACRO ADD_N_VALUES_TO_CLASS_ABC(obj, "String", 1.0, 4);
MACRO ADD_N_VALUES_TO_CLASS_ABC(obj, 1, 2.0, "String", 4.0, 3);

Also if I use variable number of arguments va_args, I lose the type information needed to call the overloaded function?

Thanks in advance.

3
Do you work with a C++11 compiler? - Andy Prowl
have a look at boost.pp or maybe even calling it as ABC((p1,p2,p3)) is enough for you. - PlasmaHH
Variadic is the keyword here. Be it variadic templates or variadic macros (the latter probably being simpler). Alternatively a minor refactor might help: ABC& add(int); and then use as obj->add(5).add("String").add(1.0) becomes slightly less cumbersome to write. - David Rodríguez - dribeas
Compiler is g++ version 4.1.2 on Linux. The ABC class is 3rd party and cannot be modified. - user2043396

3 Answers

2
votes

On a compliant C++11 compiler, you can use variadic templates to achieve that:

template<typename T>
void addValues(ABC& obj, T&& t)
{
    obj.addValue(forward<T>(t));
}

template<typename T, typename... Ts>
void addValues(ABC& obj, T&& t, Ts&&... ts)
{
    obj.addValue(forward<T>(t));
    addValues(obj, forward<Ts>(ts)...);
}

This is how you would use it:

ABC a;
add_values(a, 3, "hello", 4.5f);
0
votes

Using the C++11 feature called variadic templates (available in GCC from version 4.3) you can add the following member function:

void addValues(){}; // Base case.

template<class H, class... T>
void addValues(H&& head, T&&... tail)
{
    addValue(std::forward<H>(head));
    addValues(std::forward<T>(tail)...);
}

Example usage:

addValues(1, 2.0, "String", 4.0, 3);

is equivalent to

addValue(1); addValue(2.0); addValue("String"); addValue(4.0); addValue(3);
0
votes

Since you say you are using g++ version 4.1.2 (which is fairly old), apparently C++11 is not an option. Fortunately, you don't need it! It is possible to use variadic macros, but a much simpler and more elegant C++ solution is to think like cout, and do:

class AddTo {
  ABC *abc;
  public:
  AddTo(ABC *abc) : abc(abc) { }
  template<class T>
  const AddTo& operator<<(const T& val) const {
    abc->addValue(val);
    return *this;
  }
};

Then you can use this like:

ABC *obj = new ABC();
AddTo(obj) << 1 << 2.0 << "String" << 4.0 << 3;