I am trying to implement a function which accepts a variable number of strings and forwards to a print function, which expects a char
pointer and size
for every string, interleaved.
Example:
std::string a = "123";
std::string b = "1234";
forward(a, b); // should call doPrint(a.c_str(), a.size(), b.c_str(), b.size())
I thought that the following should be a correct implementation, but even though it compiles the behavior is very surprising to me.
template <class ...Args>
void forward(const Args & ... args) {
doPrint( (args.c_str(), args.size())...);
}
forward(a, b)
calls doPrint(3, 4)
, and not doPrint("123", 3, "1234", 4)
, as if I had written doPrint((args.size())...)
. The call to c_str()
is ignored completely by the compiler.
I tried g++
, clang
, and icc
with all yielding the same output. What is wrong with (args.c_str(), args.size())...
?
Indeed, std::make_tuple(args.c_str(), args.size())...
works as expected, but let's say I cannot change doPrint
to accept and process tuples.
The comma operator is an expression whose value is the value of the last expression.
For example:
int a = (1, 2, 3, 4, 5, 6);
assert(a == 6);
What you can try instead is using tuples:
doPrint(std::tuple_cat(std::make_tuple(argc.c_str(), args.size())...));
Then doPrint
will need to be changed to work with a tuple; it could unpack the tuple back into a parameter pack if desired or just work with the tuple directly.
Example unpacking tuple:
template <class Tuple, std::size_t ... indices>
doPrint(Tuple t, std::integer_sequence<size_t, indices...>)
{
doPrint(std::get<indices>(t)...);
}
template <class Tuple>
doPrint(Tuple t)
{
doPrint(t, std::make_index_sequence<std::tuple_size<Tuple>::value>());
}
There could be some problems with ambiguous function names so you may need to change the names of these helper functions, but hopefully this is enough for you to get going.
(args.c_str(), args.size())
is a comma-separated expression, meaning that only the last part (args.size()
) will be passed to the function.
It will then repeat this for each parameter, so it will actually call doPrint
just with the strings sizes!
You should change doPrint
to use tuples instead, otherwise you have to use some crazy template meta-programming stuff.
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