转发参数包,但总是组合N个参数

  • 本文关键字:参数 组合 转发 c++
  • 更新时间 :
  • 英文 :


是否有一种简单的方法来转换和转发参数包,最好在c++ 17中没有递归?通过变换,我的意思是将两个相邻的参数组合为一个。


template <typename T1, typename T2>
struct CombinedType {
T1 v1;
T2 v2;
};
template<typename T1, typename T2>
void print_combined(CombinedType<T1, T2> v)
{
std::cout << v.v1 << ", " << v.v2 << "n";
}
// Does the work and contains the actual implementation
template<typename T1, typename T2, typename... Types>
void do_combined(CombinedType<T1, T2> c, Types ... args)
{
print_combined(c);
print_combined(args...);
}
// Shall be only a forwarder to keep legacy code working
template<typename T1, typename T2, typename... Types>
void do_single(T1 v1, T2 v2, Types... remaining)
{
do_combined(CombinedType<T1, T2>{v1, v2});
do_combined(CombinedType<Types...>{remaining}...);
}
int main()
{
// Arguments are not necessarily of the same type
do_single('1', 2, "3", 4u, std::string("5"), '6');
}

上面的代码不能编译,但是你可以理解。

编辑:如果有一种优雅的方法可以用递归实现这一点,我愿意接受。

从c++17/c++20开始,你可以使用参数包、本地模板lambda、fold表达式和元组来相对简单地完成:

template<typename F, typename... Ts>
void for_pairs_tup(F f, std::tuple<Ts...> tup)
{
[&]<size_t... is>(std::index_sequence<is...>) {
((f(std::get<is * 2>(tup), std::get<is * 2 + 1>(tup))), ...);
}(std::make_index_sequence<sizeof...(Ts) / 2>());
}
template<typename F, typename... Ts>
void for_pairs(F f, const Ts&... ts)
{
for_pairs_tup(std::move(f), std::make_tuple(ts...));
}
// call it like:
for_pairs(
[](auto a, auto b) {
std::cout << a << ", " << b << std::endl;
},
'1', 2, "3", 4u, std::string("5"), '6'
);

不需要非递归解决方案,使用if constexpr实现非常简单:

template<typename T1, typename T2, typename... Types>
void do_single(T1 v1, T2 v2, Types... remaining)
{
print_combined(CombinedType<T1, T2>{v1, v2});
if constexpr (sizeof...(Types) > 0)
do_single(remaining...);
}

演示

最新更新