I have a simple recursive function to print each argument from a parameter pack
#include <iostream>
template<typename T, typename... Args>
void printArgs(T first, Args... rest) {
std::cout << first << " ";
if constexpr (sizeof...(rest) > 0) { // doesn't compile without constexpr
printArgs(rest...);
} else {
return;
}
}
int main() {
printArgs(1, 2, "hello");
return 0;
}
Q1: Why do I need constexpr
in the if
for the program to compile?
Q2: Shouldn't the condition be sizeof...(rest) > 1
? Because if the size is 1
and I call printArgs
again, then wouldn't rest
be empty? (is it ok for it to be empty?)
I saw similar questions, like "constexpr if" vs "if" with optimizations - why is "constexpr" needed?, but I don't see how those answers relate to my case.
I'll start with the second Q, because the answer to that also explains Q1.
Q2: Shouldn't the condition be
sizeof...(rest) > 1
? Because if the size is 1 and I callprintArgs
again, then wouldn'trest
be empty? (is it ok for it to be empty?)
Your mistake is to count T
for sizeof...(rest)
. But if you call printArgs(onlyOne)
then T
is deduced from onlyOne
and Args
is empty, and sizeof...(rest)
is 0
. Your function can be called with 1 (T first
) plus zero or more, (Args... rest
), arguments.
Q1: Why do I need constexpr in the if for the program to compile?
If you remove the constexpr
you get the following error:
<source>: In instantiation of 'void printArgs(T, Args ...) [with T = const char*; Args = {}]':
<source>:8:18: recursively required from 'void printArgs(T, Args ...) [with T = int; Args = {const char*}]'
<source>:8:18: required from 'void printArgs(T, Args ...) [with T = int; Args = {int, const char*}]'
<source>:15:14: required from here
<source>:8:18: error: no matching function for call to 'printArgs()'
8 | printArgs(rest...);
| ~~~~~~~~~^~~~~~~~~
<source>:4:6: note: candidate: 'template<class T, class ... Args> void printArgs(T, Args ...)'
4 | void printArgs(T first, Args... rest) {
| ^~~~~~~~~
<source>:4:6: note: template argument deduction/substitution failed:
<source>:8:18: note: candidate expects at least 1 argument, 0 provided
8 | printArgs(rest...);
| ~~~~~~~~~^~~~~~~~~
Because on the last recursion only 1 argument is passed to printArgs
and rest
has no elements. In that case printArgs(rest...)
fails to compile because (see above) your function can only be called with 1 or more. if constexpr
results in the false branch being discarded and the part where you call printArgs()
is never instantiated.