Calling a function and passing parameters stored in a tuple?

I want the Foo class to keep a pointer to the function that it received during construction, and call that function at some point. I turned to these two questions for help:

And, based on the answers, came up with this code:

#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 } 

If you compile with 'g ++ -std = C ++ 0x', the following line will produce the following 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 ...>&) 

What am I missing? Thanks!

+4
source share
3 answers

I solved it. It was a combination of three errors:

  • user-specified pointer error: templatetypedef
  • I had to go back to the original version of apply tuple in this post: How do I extend a tuple into the arguments of a variational matrix function? . I changed all the template parameters to ARGS... because for the tuple, function and class they are all the same. Honestly, I still don't understand why this should not work ...
  • The function pointer should have been saved as such ( void (*m_f) (ARGS...); ) instead of the std::function<void(ARGS...)> object, just like me. Of course, the constructor had to be changed, of course

Thanks for answering!

0
source

I think the problem is that applyTuple refers to the tuple as the second parameter:

 template < typename... ARGS > void applyTuple( std::function<void(ARGS...)>& f, std::tuple<ARGS...> const& t ) { apply_func<sizeof...(ARGS), ARGS...>::applyTuple( f, t ); } 

But inside run you pass a pointer to a tuple, since argument_pack is a pointer to a tuple:

 std::tuple<ARGS...> *argument_pack; 

If you change the run body to

 applyTuple<ARGS...>(m_f, *argument_pack); 

then I think your problem should disappear.

Hope this helps!

+2
source

You cannot say apply_func<N-1>::... This will create the structure using ARGS = {} , so the "candidate expects 2 arguments, 5 provided errors".

In addition, in applyTuple you used apply_func<sizeof...(ARGS), ARGS...>::applyTuple , which expects to take 4 parameters: the function f , the tuple t and ARGS... args , but you cannot pass arguments so the "candidate expects 4 arguments, 2 provided" error.

As an alternative solution, you can use my vtmp library and use

 template<typename... ARGS> void Foo<ARGS...>::run() { utils::tuple_apply(*argument_pack, m_f); } 

(Note: g ++ 4.7 is required)

0
source

Source: https://habr.com/ru/post/1395370/


All Articles