Reputation: 2308
I write a variadic template to print all the arguments with recursion:
#include <iostream>
using std::ostream; using std::istream;
using std::cin; using std::cout; using std::endl;
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
if (sizeof...(rest)) {
os << t << ", ";
return myprint(os, rest...);
}
else
return os << t;
}
int main(int argc, char *argv[]) {
myprint(cout, "hello");
return 0;
}
But when I compiles it with g++ -std=c++1y
, it complains:
error: no matching function for call to ‘myprint(std::ostream&)’
return myprint(os, rest...);
In the function myprint
, I have checked the value of sizeof...(rest)
. And when it is 0, it will not call myprint(os, rest...)
. So I don't know why it will call myprint(std::ostream&)
.
And I have also searched for the related question, I have found that it needs a base case. But why do I need a base case, and can't sizeof...
work in a variadic template?
And for the simple indefinite recursive case:
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
os << t << ", "; // print the first argument
return print(os, rest...); // recursive call; print the other arguments
}
The code above can't be compiled at all for the same error.
Upvotes: 1
Views: 238
Reputation: 172914
For the if statement you used, both the statement-true and statement-false must be valid, whether the condition yields to the result of true
or false
.
You can use constexpr if since C++17; when the value of condition is false
, the statement-true will be discarded. e.g.
if constexpr (sizeof...(rest)) {
os << t << ", ";
return myprint(os, rest...);
}
else
return os << t;
If you can't use C++17, you can add another template overload for the case that the number of arguments is only one, to stop the recursion, e.g.
template <typename T>
ostream &myprint(ostream &os, const T &t) {
return os << t;
}
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
os << t << ", ";
return myprint(os, rest...);
}
Upvotes: 4
Reputation: 21131
songyuanyao's answer explains why it's invalid and provides a solution for C++17. Alternatively, you could have a base case to myprint
prior to that.
template <typename T>
ostream &myprint(ostream &os, const T &t) {
return os << t;
}
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
os << t << ", ";
return myprint(os, rest...);
}
Upvotes: 2