Variadic Templates - How Can I Create a Type That Stores Passed Arguments

So, suppose I have a class containing a functional object, and in the constructor call I pass arguments that will be passed to the functional object after some time. Sort of:

class Binder{ public: Binder(functional_object, listOfParameters); callFunctionalObject(); // calls functional object with given list of parameters }; 

Prior to C ++ 11, I could not use Variadic templates, so one could do:

 struct none{}; template <typename T1, typename T2=none, typename T3=none> class Binder{ public: Binder(T1 functionalObject, T2 arg1=none(), T3arg3=none()); void callFunctionalObject(); private: T1 m_functionalObject; T2 m_arg1; T3 m_arg2; }; 

Where callFunctionalobject can be implemented as follows:

 template<typename T1, typename T2, typename T3> void Binder<T1,T2,T3>::callFunctionalObject(){ callImpl(m_functionalObject, m_arg1, m_arg2); } 

and callImpl will be overloaded to recognize objects of type none to pass the required number of arguments to the function object.

Now switching to C ++ 11 I don’t know how to realize the fact that in a private section I have members to which I have direct access.

Can someone explain to me how I can do the same with C ++ 11 or C ++ 14?

+5
source share
3 answers

You must save std::function and std::tuple and then call the function in the tuple.

Here's a working C ++ solution 14

 #include <iostream> #include <functional> template<typename T1, typename ...T> class Binder { public: Binder(std::function<T1(T...)> f, std::tuple<T...> t) : m_functional_obj(f), m_parameters(t) {} template<std::size_t ...I> T1 callImpl(std::index_sequence<I...>) { return m_functional_obj(std::get<I>(m_parameters)...); } T1 callFunctionalObject() { return callImpl(std::index_sequence_for<T...>{}); } private: std::function<T1(T...)> m_functional_obj; std::tuple<T...> m_parameters; }; int test(int i) { std::cout << "test(" << i << ")" << std::endl; return i + 1; } int main() { Binder<int,int> bibi(test, std::make_tuple<int>(2)); auto res = bibi.callFunctionalObject(); std::cout << "res is " << res << std::endl; } 

Living code

+7
source

My example:

 // Indices template <std::size_t... Is> struct Indices {}; template <std::size_t N, std::size_t... Is> struct BuildIndices : BuildIndices <N - 1, N - 1, Is...> {}; template <std::size_t... Is> struct BuildIndices<0, Is...> : Indices < Is... > {}; template<class FuncObject, class ... T> class Binder { public: Binder(FuncObject funcObject, T... args) : m_funcObject(funcObject), m_arguments(std::make_tuple(args...)) { } void Call() { DoCall(BuildIndices<sizeof ... (T)> {}); } private: template<size_t... Ind> void DoCall(Indices<Ind...>) { return m_funcObject(std::get<Ind>(m_arguments)...); } FuncObject m_funcObject; std::tuple<T...> m_arguments; }; void Foo(int, char) { } int main() { Binder<void(*)(int, char), int, char> f(Foo, 1, 'd'); f.Call(); return 0; } 
+4
source

The easiest way is to save the std::function object with the arguments already set using std::bind :

 class Binder{ public: template <typename T1, typename... T2> Binder(T1 functionalObject, T2... args) : f(std::bind(functionalObject, args...)) {} void callFunctionalObject() { f(); } private: std::function<void()> f; }; void foo(int n, std::string s) { std::cout << n << " " << s << std::endl; } int main() { Binder b(foo, 42, "test"); b.callFunctionalObject(); } 

If you need something more advanced, you may want to save the function arguments and std::tuple , and then use the layout of the template to expand it, but please specify what exactly you need in the question.

PS See also "unpacking" a tuple to call the corresponding function pointer

+2
source

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


All Articles