13

I have the following template function with specialization:

// Pass the argument through ...
template<typename T, typename U=T>
U convert(T&& t) {
  return std::forward<T>(t);
}

// ... but convert std::strings
const char* convert(std::string s) {
  return s.c_str();
}

If I then have a variadic template function like:

template<typename ... Args>
void doSomething(Args ... args) {
  // Convert parameter pack using convert function above
  // and call any other variadic templated function with
  // the converted args.
}

Is there any way to convert the parameter pack using the convert function as in the comment?

My original goal was being to be able to pass std::string to '%s' in a printf like function without having to manually calling .c_str() on the strings first. But I am also interested in general if this can be done in a simple way, my tries so far failed.

Zitrax
  • 19,036
  • 20
  • 88
  • 110

1 Answers1

19
template<typename ... Args>
void doSomething(Args ... args) {
  something(convert(args)...);
}

Where something(convert(args)...) is a parameter pack expansion that expands to:

// pseudocode
something(convert(arg0), convert(arg1), convert(arg2), ...)

BTW, you might want to take args by forwarding references in order to avoid unnecessary copies and to properly propagate lvalue references:

template<typename... Args>
void doSomething(Args&& ... args) {
  something(convert(std::forward<Args>(args))...);
}
Zitrax
  • 19,036
  • 20
  • 88
  • 110
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • I think it's worth noting that `something(convert(arg0), convert(arg1), convert(arg2), ...)` is not guarranteed to execute convert() in order from left-to-right. I think using initalizer-lists instead would force left-to-right execution: [see here](https://stackoverflow.com/questions/20266153/stdinitializer-list-and-order-of-evaluation-of-the-elements) – trev Mar 16 '22 at 16:00