多个可变模板功能

Multiple variadic templates function

本文关键字:功能      更新时间:2023-10-16

假设我有两个函数f1()f2(),定义如下:

template<class ... Types> void f1(Types ... args1)
template<class ... Types> void f2(Types ... args2)

现在我想创建第三个函数f3(),它接受输入f1()f2(),我如何用args1...args2...定义f3()

template<class F1, class F2> void f3(F1 f1, F2 f2) {
f1();  // how do I call f1? I need to pass in the args... 
}    

你不能。

因为模板函数是一组函数。你可以传递一个函数,解释模板类型,

f3(f1<int, long, long>, f2<char, int>);

而不是全套功能。

我能建议的最好的方法是将你的模板函数封装在structs 中

struct s1
{
template <typename ... Types>
static void f1 (Types ... args1)
{ }
};
struct s2
{
template <typename ... Types>
static void f2 (Types ... args2)
{ }
};

因此您可以将传递给f3()s1s2对象

s1  a;
s2  b;
f3(a, b);

或者只是类型

f3<s1, s2>();

正如Jarod42所建议的,您还可以将f1()f2()封装在几个Lambda(仅来自C++14)中

auto l1 = [](auto&& ... args) { f1(std::forward<decltype(args)>(args)...); };
auto l2 = [](auto&& ... args) { f2(std::forward<decltype(args)>(args)...); };
f3(l1, l2)

我的意思是,当我调用f3时,我提供f1和f2。我还需要传入f1和f2的参数。我该怎么做?

但是f1()f2()的参数是相同的?还是两套不同的?

在第一种情况下,您可以将它们作为模板变量参数传递;(按照Jarod42的建议)

template <typename L1, typename L2, typename ... Args>
void f3 (L1 l1, L2 l2, Args const & ... as)
{
L1(as...);
L2(as...);
}  
auto l1 = [](auto&& ... args) { f1(std::forward<decltype(args)>(args)...); };
auto l2 = [](auto&& ... args) { f2(std::forward<decltype(args)>(args)...); };
f3(l1, l2, 1, '2', 3L, 4ULL);

如果您需要两个不同的参数集,则需要将这些参数包装在std::tuple或类似的文件中。

template <typename L1, typename L2, typename ... As1, typename ... As2>
void f3 (L1 l1, L2 l2, std::tuple<As1...> const & t1, std::tuple<As2...> const & t2)
{
std::apply(l1, t1);
std::apply(l2, t2);
}  
auto l1 = [](auto&& ... args) { f1(std::forward<decltype(args)>(args)...); };
auto l2 = [](auto&& ... args) { f2(std::forward<decltype(args)>(args)...); };
f3(l1, l2, std::make_tuple(1, 2l, '3'), std::make_tuple('4', 5ull));

但考虑到std::apply()只能从C++17中获得:之前从元组中提取参数有点复杂。

如果没有c++17,我该如何做到这一点?

下面是一个完整的C++14示例,它使用std::index_sequence_forstd::index_sequence对元组进行解包

#include <tuple>
#include <iostream>
#include <type_traits>
template <typename ... Ts>
void f1 (Ts ... as)
{ std::cout << "- f1: " << sizeof...(Ts) << " arguments" << std::endl; }
template <typename ... Ts>
void f2 (Ts ... as)
{ std::cout << "- f2: " << sizeof...(Ts) << " arguments" << std::endl; }
template <typename L, typename ... Ts, std::size_t ... Is>
void f3_helper (L l, std::tuple<Ts...> const & t, std::index_sequence<Is...>)
{ l(std::get<Is>(t)...); }
template <typename L1, typename L2, typename ... As1, typename ... As2>
void f3 (L1 l1, L2 l2, std::tuple<As1...> const & t1,
std::tuple<As2...> const & t2)
{
f3_helper(l1, t1, std::index_sequence_for<As1...>{});
f3_helper(l2, t2, std::index_sequence_for<As2...>{});
}  
int main()
{
auto l1 = [](auto && ... args)
{ f1(std::forward<decltype(args)>(args)...); };
auto l2 = [](auto && ... args)
{ f2(std::forward<decltype(args)>(args)...); };
f3(l1, l2, std::make_tuple(1, 2l, '3'), std::make_tuple('4', 5ull));
}