参数包递归函数中constexpr if的必要性及条件疑问
C++ 参数包递归打印函数的技术疑问解答
先贴出你编写的代码:
#include <iostream> template<typename T, typename... Args> void printArgs(T first, Args... rest) { std::cout << first << " "; if constexpr (sizeof...(rest) > 0) { // 不加constexpr无法编译 printArgs(rest...); } else { return; } } int main() { printArgs(1, 2, "hello"); return 0; }
Q1:为何该if语句中必须添加constexpr才能使程序编译通过?
普通if语句在模板实例化阶段,两个分支的代码都会被编译器尝试实例化,哪怕其中一个分支在运行时永远不会执行。
在你的代码里,当参数包rest为空时,printArgs(rest...)等价于调用无参的printArgs(),但你的模板函数要求至少传入一个参数(T first是必填项),编译器尝试实例化这个无参调用时会直接报错。
而if constexpr是编译时条件判断,编译器只会实例化符合条件的分支:当sizeof...(rest) > 0为真时,才会实例化递归调用的分支;当条件为假时,递归分支的代码会被直接丢弃,不会触发无参printArgs的实例化,因此能正常编译。
Q2:递归条件是否应该改为sizeof...(rest) > 1?当rest大小为1时调用printArgs,rest会变为空,这种情况是否合法?
完全不需要修改条件,当前的sizeof...(rest) > 0是正确的,且rest变为空的情况完全合法:
- 当
rest大小为1时,调用printArgs(rest...)会实例化printArgs模板,此时T是该参数的类型,Args...为空参数包——C++的可变参数模板本身支持空包,所以这个调用是合法的。 - 进入这个实例化后的函数时,会先打印
first(也就是原rest里的那个参数),然后判断sizeof...(rest)为0,直接return,不会触发无效的递归调用。
如果改成sizeof...(rest) > 1,反而会导致最后一个参数无法被打印:比如调用printArgs(1,2,"hello")时,第二次递归的rest大小为1,此时条件不成立,不会调用printArgs("hello"),最终只会打印1 2 ,漏掉第三个参数。
内容的提问来源于stack exchange,提问作者koegl
相关产品推荐
相关产品推荐

