我打算实现一个模板函数,它接受两个函数及其参数列表,然后创建两个包装器。我已经实现了类似的解决方案来接受两个函数并使用std::bind()
创建包装器但使用硬编码参数。解决方案是这样的:
template <typename T1, typename T2, typename T3, typename T4>
myWrapper (T2 func1, T4 func2) {
std::function<T1>ff = std::bind(func1, 1, placeholders::_1);
std::function<T3>ff = std::bind(func1, 110, 20, "something");
}
如您所见,std::bind()
的参数在两种情况下都是硬编码的,我希望通过myWrapper()
函数读取它们。有没有办法读取两个可变参数模板(任意长度和类型的变量列表)并将它们发送到上面代码中的两个std::bind()
调用?
谢谢,
丹
答案 0 :(得分:2)
关于variadicStruct
的想法,您可以查看std::tuple
。
template<class... Ts, class... Us>
void do_stuff(const std::tuple<Ts...>&, const std::tuple<Us...>&) {
std::cout << "two variadic packs with " << sizeof...(Ts)
<< " and " << sizeof...(Us) << " elements." << std::endl;
}
这样称呼:
do_stuff(std::make_tuple(4.7, 'x', 1.0, 4, 8l), std::make_tuple("foo", 1));
答案 1 :(得分:2)
不确定你想要什么,但我想你需要使用std::tuple
(或类似的东西)来分隔两个args序列。
以下是我的意思的完整工作示例,根据我对您想要的内容的理解。
#include <tuple>
#include <string>
#include <utility>
#include <iostream>
#include <functional>
template <typename T1, typename T2, typename T3, typename T4,
typename ... Ts1, typename ... Ts2,
std::size_t ... Is1, std::size_t ... Is2>
auto myWrapperH (T3 func1, T4 func2, std::tuple<Ts1...> const & tp1,
std::tuple<Ts2...> const & tp2,
std::index_sequence<Is1...> const &,
std::index_sequence<Is2...> const &)
{
T1 f1 = std::bind(func1, std::get<Is1>(tp1)...);
T2 f2 = std::bind(func2, std::get<Is2>(tp2)...);
return std::make_pair(f1, f2);
}
template <typename T1, typename T2, typename T3, typename T4,
typename ... Ts1, typename ... Ts2>
auto myWrapper (T3 func1, T4 func2, std::tuple<Ts1...> const & tp1,
std::tuple<Ts2...> const & tp2)
{ return myWrapperH<T1, T2>(func1, func2, tp1, tp2,
std::make_index_sequence<sizeof...(Ts1)>{},
std::make_index_sequence<sizeof...(Ts2)>{}); }
int foo (int a, int b)
{ return a+b; }
std::size_t bar (int a, int b, std::string const & str)
{ return str.size() + a + b; }
int main ()
{
using fType1 = std::function<int(int)>;
using fType2 = std::function<long()>;
auto mwr = myWrapper<fType1, fType2>(&foo, &bar,
std::make_tuple(1, std::placeholders::_1),
std::make_tuple(110, 20, std::string{"something"}));
std::cout << mwr.first(5) << std::endl; // print 6
std::cout << mwr.second() << std::endl; // print 139
}
不幸的是C ++ 14代码(auto
返回类型; std::index_sequence
和std::make_index_sequence
),但在C ++ 11中应该很容易适应。
- 编辑 -
正如Banan指出的那样(谢谢!),没有必要明确返回函数的类型(T1
,T2
)。
使用auto
返回类型,示例可以简化如下
#include <tuple>
#include <string>
#include <utility>
#include <iostream>
#include <functional>
template <typename F1, typename F2, typename ... Ts1, typename ... Ts2,
std::size_t ... Is1, std::size_t ... Is2>
auto myWrapperH (F1 func1, F2 func2, std::tuple<Ts1...> const & tp1,
std::tuple<Ts2...> const & tp2,
std::index_sequence<Is1...> const &,
std::index_sequence<Is2...> const &)
{ return std::make_pair(std::bind(func1, std::get<Is1>(tp1)...),
std::bind(func2, std::get<Is2>(tp2)...)); }
template <typename F1, typename F2, typename ... Ts1, typename ... Ts2>
auto myWrapper (F1 func1, F2 func2, std::tuple<Ts1...> const & tp1,
std::tuple<Ts2...> const & tp2)
{ return myWrapperH(func1, func2, tp1, tp2,
std::make_index_sequence<sizeof...(Ts1)>{},
std::make_index_sequence<sizeof...(Ts2)>{}); }
int foo (int a, int b)
{ return a+b; }
std::size_t bar (int a, int b, std::string const & str)
{ return str.size() + a + b; }
int main ()
{
auto mwr = myWrapper(&foo, &bar,
std::make_tuple(1, std::placeholders::_1),
std::make_tuple(110, 20, std::string{"something"}));
std::cout << mwr.first(5) << std::endl; // print 6
std::cout << mwr.second() << std::endl; // print 139
}
答案 2 :(得分:1)
您可以使用std::make_tuple
和std::apply
,例如:
template <typename R, typename Func1, typename Args1>
void wrapper (Func1 f1, Args1 a1)
{
std::function<R> wrapped1 = [f1, a1]{ return std::apply(f1, a1); };
}
// ...
auto deg_to_rad = [](int x){ return x / 180.f * 3.1415f; };
wrapper<float>(deg_to_rad, std::make_tuple(45));
std::apply
需要C ++ 17支持。但是,linked page on cppreference包含一个可在C ++ 11中使用的实现。