调用函数并传递存储在元组中的参数?
问题描述:
我想要一个Foo类来存储一个构造函数指针,并在某个时候调用这个函数。我看着这两个问题求助:调用函数并传递存储在元组中的参数?
- Pass tuple's content as variadic function arguments
- How do I expand a tuple into variadic template function's arguments?
,并根据问题的答案,想出了这个代码:
#include <functional>
template < int N, typename... ARGS >
struct apply_func {
static void applyTuple(std::function<void(ARGS...)>& f,
const std::tuple<ARGS...>& t,
ARGS... args) {
apply_func<N-1>::applyTuple(f, t, std::get<N-1>(t), args...);
}
};
template <typename... ARGS>
struct apply_func<0,ARGS...>
{
static void applyTuple(std::function<void(ARGS...)>& f,
const std::tuple<ARGS...>& /* t */,
ARGS... args) {
f(args...);
}
};
template < typename... ARGS >
void applyTuple(std::function<void(ARGS...)>& f,
std::tuple<ARGS...> const& t) {
apply_func<sizeof...(ARGS), ARGS...>::applyTuple(f, t);
}
template<typename... ARGS>
class Foo
{
std::function<void(ARGS...)> m_f;
std::tuple<ARGS...> *argument_pack;
public:
Foo(std::function<void(ARGS...)> f):m_f(f){}
void operator()(ARGS... args);
void run();
};
template<typename... ARGS>
void Foo<ARGS...>::operator()(ARGS... args)
{
m_f(args...); // this works
}
template<typename... ARGS>
void Foo<ARGS...>::run()
{
applyTuple<ARGS...>(m_f, *argument_pack); // this doesn't compile
}
void bar(int i, double d){}
int main(void)
{
Foo<int,double> foo(bar);
foo(1,1.0); // this works
foo.run(); // this doesn't compile
}
如果用编译'g ++ -std = C++ 0x' next next to last line will give this error:
test.cc: In function ‘void applyTuple(std::function<void(ARGS ...)>&, const std::tuple<_Elements ...>&) [with ARGS = {int, double}]’:
test.cc:52:9: instantiated from ‘void Foo<ARGS>::run() [with ARGS = {int, double}]’
test.cc:61:17: instantiated from here
test.cc:27:8: error: no matching function for call to ‘apply_func<2, int, double>::applyTuple(std::function<void(int, double)>&, const std::tuple<int, double>&)’
test.cc:27:8: note: candidate is:
test.cc:6:19: note: static void apply_func<N, ARGS>::applyTuple(std::function<void(ARGS ...)>&, const std::tuple<_Elements ...>&, ARGS ...) [with int N = 2, ARGS = {int, double}]
test.cc:6:19: note: candidate expects 4 arguments, 2 provided
test.cc: In static member function ‘static void apply_func<N, ARGS>::applyTuple(std::function<void(ARGS ...)>&, const std::tuple<_Elements ...>&, ARGS ...) [with int N = 2, ARGS = {int, double}]’:
test.cc:27:8: instantiated from ‘void applyTuple(std::function<void(ARGS ...)>&, const std::tuple<_Elements ...>&) [with ARGS = {int, double}]’
test.cc:52:9: instantiated from ‘void Foo<ARGS>::run() [with ARGS = {int, double}]’
test.cc:61:17: instantiated from here
test.cc:9:9: error: no matching function for call to ‘apply_func<1>::applyTuple(std::function<void(int, double)>&, const std::tuple<int, double>&, const double&, int&, double&)’
test.cc:9:9: note: candidate is:
test.cc:6:19: note: static void apply_func<N, ARGS>::applyTuple(std::function<void(ARGS ...)>&, const std::tuple<_Elements ...>&, ARGS ...) [with int N = 1, ARGS = {}]
test.cc:6:19: note: candidate expects 2 arguments, 5 provided
test.cc: In static member function ‘static void apply_func<N, ARGS>::applyTuple(std::function<void(ARGS ...)>&, const std::tuple<_Elements ...>&, ARGS ...) [with int N = 1, ARGS = {}]’:
test.cc:9:9: instantiated from ‘static void apply_func<N, ARGS>::applyTuple(std::function<void(ARGS ...)>&, const std::tuple<_Elements ...>&, ARGS ...) [with int N = 2, ARGS = {int, double}]’
test.cc:27:8: instantiated from ‘void applyTuple(std::function<void(ARGS ...)>&, const std::tuple<_Elements ...>&) [with ARGS = {int, double}]’
test.cc:52:9: instantiated from ‘void Foo<ARGS>::run() [with ARGS = {int, double}]’
test.cc:61:17: instantiated from here
test.cc:9:9: error: no matching function for call to ‘get(const std::tuple<>&)’
test.cc:9:9: note: candidates are:
/usr/include/c++/4.6/utility:133:5: note: template<long unsigned int _Int, class _Tp1, class _Tp2> typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type& std::get(std::pair<_Tp1, _Tp2>&)
/usr/include/c++/4.6/utility:138:5: note: template<long unsigned int _Int, class _Tp1, class _Tp2> const typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type& std::get(const std::pair<_Tp1, _Tp2>&)
/usr/include/c++/4.6/tuple:531:5: note: template<long unsigned int __i, class ... _Elements> typename std::__add_ref<typename std::tuple_element<__i, std::tuple<_Elements ...> >::type>::type std::get(std::tuple<_Elements ...>&)
/usr/include/c++/4.6/tuple:538:5: note: template<long unsigned int __i, class ... _Elements> typename std::__add_c_ref<typename std::tuple_element<__i, std::tuple<_Elements ...> >::type>::type std::get(const std::tuple<_Elements ...>&)
我错过了什么?谢谢!
答
我解决它。这是三个错误的组合:
- 指针错误所指出的用户:templatetypedef
- 我不得不回去后这一应用的元组的原始版本:How do I expand a tuple into variadic template function's arguments?。我将所有模板参数改为
ARGS...
,因为对于元组,函数和类他们都是一样的。老实说,我仍然不明白为什么这不应该工作... - 函数指针必须像这样存储(
void (*m_f) (ARGS...);
)而不是像我一样存储std::function<void(ARGS...)>
对象。构造者必须相应地改变,当然
谢谢你的回答!
答
我认为这个问题是applyTuple
需要参考元组作为其第二个参数:
template < typename... ARGS >
void applyTuple(std::function<void(ARGS...)>& f,
std::tuple<ARGS...> const& t) {
apply_func<sizeof...(ARGS), ARGS...>::applyTuple(f, t);
}
但,run
里面,你传递一个指针元组,由于argument_pack
是指针指向一个元组:
std::tuple<ARGS...> *argument_pack;
如果更改run
身体要
applyTuple<ARGS...>(m_f, *argument_pack);
然后我认为你的问题应该消失。
希望这会有所帮助!
答
你不能说apply_func<N-1>::...
。这将用ARGS = {}
实例化结构,因此“候选人期待2个参数,5个提供”错误。
此外,在applyTuple
,你已经使用apply_func<sizeof...(ARGS), ARGS...>::applyTuple
,这预计将接受4个参数:功能f
,元组t
和ARGS... args
,但你无法通过ARGS,因此“候选预计4个参数, 2提供了“错误。
作为一个替代的解决方案,你可以用我的vtmp库,并使用
template<typename... ARGS>
void Foo<ARGS...>::run()
{
utils::tuple_apply(*argument_pack, m_f);
}
(注:需要G ++ 4.7)
你能编辑你的答案来包含你的工作解决方案吗? – 2013-03-08 21:45:40