As part of a logging library, I would like to be able to iterate a parameter pack, writing each value to a stream. My first attempt doesn't compile however. The first error is "error C2144: syntax error : 'int' should be preceded by '}'".
#include <sstream>
#include <ostream>
#include <iomanip>
#include <fstream>
template <typename ...Args>
std::ostream & Write(std::ostream & o, std::initializer_list<Args...> list)
{
size_t size = list.size();
if(list.size() > 0)
{
for(size_t i = 0; i < (size - 1); i++)
o << list[i] << ", ";
o << list[i];
}
return o;
}
template<typename ...Args>
std::ostream & Write(std::ostream & o, Args...)
{
return Write(o, { Args... });
}
int main(int argc, wchar_t * argv[])
{
std::ostringstream o;
Write(o, 1, "Hello", 2, "World", 3, 1.4857);
// o should contain the string of characters "1, Hello, 2, World, 3, 1.4857"
return 0;
}
How do I iterate each item in ... and send it to the stream?
A function parameter pack is a function parameter that accepts zero or more function arguments. A template with at least one parameter pack is called a variadic template.
Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.
Variadic functions are functions (e.g. printf) which take a variable number of arguments.
Recursion is one option:
template<typename Arg>
std::ostream & Write(std::ostream & o, Arg&& arg) {
return o << std::forward<Arg>(arg);
}
template<typename Arg, typename ...Args>
std::ostream & Write(std::ostream & o, Arg&& arg, Args&&... args)
{
o << std::forward<Arg>(arg) << ", ";
return Write(o, std::forward<Args>(args)...);
}
Demo.
Alternatively, the pack expansion trick still works, with a little tweak - you need to special-case the first item in the list:
template<typename Arg, typename ...Args>
std::ostream & Write(std::ostream & o, Arg&& arg, Args&&... args)
{
o << std::forward<Arg>(arg);
using expander = int[];
(void) expander{ (o << ", " << std::forward<Args>(args), void(), 0)... };
return o;
}
Demo.
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