假设我有两个函数 f1()
和 f2()
定义如下:
template<class ... Types> void f1(Types ... args1)
template<class ... Types> void f2(Types ... args2)
现在我想创建第三个函数 f3()
接受输入 f1()
和 f2()
,我该如何定义f3()
同时包含 args1...
和 args2...
?
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>);
而不是全套功能。
我能建议的最好的方法是将模板函数包装在结构中
struct s1
{
template <typename ... Types>
static void f1 (Types ... args1)
{ }
};
struct s2
{
template <typename ... Types>
static void f2 (Types ... args2)
{ }
};
所以你可以传递给 f3()
s1
和 s2
对象
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)
what I mean is when I call f3, I offer f1 and f2. I also need to pass in the params for f1 and f2. How do I do that?
但是 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:之前从元组中提取参数有点复杂。
how do I do that without c++17?
以下是使用 std::index_sequence_for
和 std::index_sequence
解包元组的完整 C++14 示例
#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));
}