Reputation: 37834
Here is a variadic template that prints parameters.
#include <string>
#include <iostream>
void Output() {
std::cout<<std::endl;
}
template<typename First, typename ... Strings>
void Output(First arg, const Strings&... rest) {
std::cout<<arg<<" ";
Output(rest...);
}
int main() {
Output("I","am","a","sentence");
Output("Let's","try",1,"or",2,"digits");
Output(); //<- I do not want this to compile, but it does.
return 0;
}
Is there a way to get this functionality without having the "no parameter" call work, and without having to write two functions every time?
Upvotes: 1
Views: 187
Reputation: 2079
As far as I see there are two questsions:
Output()
calls with no parameters.My solution to item 1 is as follows:
template<typename T>
void Output(const T & string) {
std::cout<<string<<std::endl;
}
template<typename First, typename ... Strings>
void Output(const First & arg, const Strings & ... rest) {
std::cout<<arg<<" ";
Output(rest...);
}
Basically, instead of ending the recursion when the template list is empty, I end it when it only contains one type. There is one difference between the above and the code from the question: if does not output any space after the last item. Instead it just outputs the newline.
For question number two see the answer by Daniel Frey above. I really liked this solution, although it took some time to grasp it (and I upvoted the answer). At the same time I find that it makes the code harder to read/understand and therefore harder to maintain. Currently I would not not use that solution in anything but small personal code snippets.
Upvotes: 2
Reputation: 56863
You might want to keep the separation of the first and the rest of the parameters, you can use:
template<typename First, typename ... Rest>
void Output(First&& first, Rest&&... rest) {
std::cout << std::forward<First>(first);
int sink[]{(std::cout<<" "<<std::forward<Rest>(rest),0)... };
(void)sink; // silence "unused variable" warning
std::cout << std::endl;
}
Note that I used perfect forwarding to avoid copying any parameters. The above has the additional benefit to avoid recursion and therefore is likely to produce better (faster) code.
The way I wrote sink
also guarantees that the expressions expanded from rest
are evaluated left-to-right - which is important when compared to the naïve approach of just writing a helper function template<typename...Args>void sink(Args&&...){}
.
Upvotes: 3
Reputation: 18750
Call the function from a forwarding type function and have a static_assert like this:
template <typename ... Args>
void forwarder(Args ... args) {
static_assert(sizeof...(args),"too small");
Output(args...);
}
Upvotes: 2