There is a sequence of three types, say std::string, int, int. Is there a template in C++ to allow a function to take an infinite number of that sequence as parameters?
Function("Peter", 27, 89,
"Max", 25, 72,
"Frank", 32, 94,
"David", 31, 98);
The problem is "what do you have to do with that sequence".
It is possible to take an arbitrary sequence of parameters and giving them 3 by 3 to a function taking just 3:
void Function(string n, int a, int b)
{ /* base action here */ }
template<class... Others>
void Function(string n1, int a1, int b1, const Others&... t)
{
Function(n1, a1, b1);
Function(t...);
}
It compiles only if the parameter types matches repeatedly the base function ones.
Here are several ways that came to my mind:
variadic templates: C++11
(covered by Emilio Garavaglia's answer, so I won't repeat)
initializer_lists: C++11
(similar to ChriZzZ's answer, but instead using std::initializer_list directly)
struct Sequence {
std::string name;
int numberA;
int numberB;
};
#include <initializer_list>
void Function(std::initializer_list<Sequence> aLotOfData)
{
for(const Sequence& s : aLotOfData)
{
// do operations on s.name, s.numberA, s.numberB
}
}
//usage example
Function({ {"Peter", 27, 89}, {"Max", 25, 72} });
(here ends the list of straightforward solutions)
overloading functions for arguments up to N:
void Function(string n1, int a1, int b1) { /* ??? */ }
void Function(string n1, int a1, int b1, string n2, int a2, int b2) { /* ??? */ }
void Function(string n1, int a1, int b1, string n2, int a2, int b2, string n3, int a3, int b3) { /* ??? */ }
//usage example
Function("Peter", 27, 89, "Max", 25, 72);
Actually it's not that bad - if you can assume no one will call it with more than N args (bit of trivia: C standard recommends for C compilers to support minimum limit of 128 arguments) and that you won't code it manually (use preprocessor, but not necessarily the C preprocessor - because it's lowest common denominator for preprocessing. Boost uses its own preprocessor for variable arguments in non-C++11 code. Or you can generate C++ code with C++ program and include the output file in source code - now that's C++ metaprogramming ;-) ).
array initialization and passing to function (or alternatively, with pointers and sizeof):
struct Sequence
{
std::string name;
int numberA;
int numberB;
};
#include <cstddef>
template<std::size_t N>
void Function(Sequence (&data)[N])
{
for(std::size_t i = 0; i < N; ++i)
{
// do operations on data[i].name, data[i].numberA, data[i].numberB
}
}
//usage example
Sequence args[] = { {"Peter", 27, 89}, {"Max", 25, 72} };
Function(args);
Similar solution can be used in C. (in C99 you can even use compound literals to supply arguments inline)
method/function/operator chaining:
struct Function
{
const Function& operator()(string name, int na, int nb) const
{
// do operations to name, na, nb
return *this;
}
void operator() const
{
//base case
//optional here - return values
}
};
//usage example
Function()("Peter", 27, 89)("Max", 25, 72)();
Chaining is used in C++ iostreams and in Boost.Assign. In this implementation, caller can forget to include the last parens, and function won't do the final things - there is sure to be better implementation.
C varargs:
#include <cstdarg>
void Function(std::size_t count, ...)
{
va_list ap;
va_start(ap, count);
for(std::size_t i = 0; i < count; ++i)
{
string name = va_arg(ap, const char*);
int na = va_arg(ap, int);
int nb = va_arg(ap, int);
// do operations on name, na, nb
}
va_end(ap);
}
//usage example (the first argument refers to count of arguments - it has to match)
Function(2, "Peter", 27, 89, "Max", 25, 72);
Very, very bad solution. We had to discard std::string as argument and replace it with const char* as non-PODs can't be passed to varargs function (or we could pass pointers to std::string). Note that any mistake here will cause undefined behaviour. The compiler won't check type of args and will blindly trust us that we passed arguments of the right type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With