迭代参数包
通常,我们需要对可变参数模板参数包中的每个元素执行操作。有很多方法可以做到这一点,并且使用 C++ 17 可以更轻松地读取和写入解决方案。假设我们只想打印包中的每个元素。最简单的解决方案是递归:
Version >= C++ 11
void print_all(std::ostream& os) {
// base case
}
template <class T, class... Ts>
void print_all(std::ostream& os, T const& first, Ts const&... rest) {
os << first;
print_all(os, rest...);
}
我们可以使用扩展器技巧,在单个函数中执行所有流式传输。这样做的优点是不需要第二次过载,但缺点是可靠性低于恒星:
Version >= C++ 11
template <class... Ts>
void print_all(std::ostream& os, Ts const&... args) {
using expander = int[];
(void)expander{0,
(void(os << args), 0)...
};
}
有关其工作原理的说明,请参阅 TC 的优秀答案 。
Version >= C++ 17
使用 C++ 17,我们在我们的工具库中获得了两个强大的新工具来解决这个问题。第一个是 fold-expression:
template <class... Ts>
void print_all(std::ostream& os, Ts const&... args) {
((os << args), ...);
}
第二个是 if constexpr
,它允许我们在一个函数中编写我们的原始递归解决方案:
template <class T, class... Ts>
void print_all(std::ostream& os, T const& first, Ts const&... rest) {
os << first;
if constexpr (sizeof...(rest) > 0) {
// this line will only be instantiated if there are further
// arguments. if rest... is empty, there will be no call to
// print_all(os).
print_all(os, rest...);
}
}