Function pointer with variable template arguments

Referring to the code below, someone can figure out how to adapt

template <typename RET, typename... ARGS1, typename... ARGS2> RET Mediator::change (Object* o, RET (Object::*f)(ARGS1...), ARGS2&&... args) { const std::tuple<ARGS2...> t(args...); for (Object* x : objects) (x->*f)(std::get<0>(t), o->rating, std::get<1>(t), o->str); } 

so I don’t need to rewrite different versions of this every time ARGS2 ... needs to be changed. I do not mind doing this when the argument consists of only 4 parameters, but you can imagine that a generalization would be necessary if it were much more than 4. Types in ARGS1 ... must consist of different types, therefore there is a way to get std :: get <0> (t), std :: get <1> (t), ... is correctly placed, so there is no need to do it manually as described above (even if there were duplicate types, then they can simply be placed in the first duplicate slot). The full code is given below (the context is that as each subscriber of the Object to the intermediary changes, the other subscribers of the Object for the Intermediary must change accordingly):

 #include <iostream> #include <string> #include <vector> #include <tuple> struct Mediator { std::vector<struct Object*> objects; void registerObject (Object* o) {objects.emplace_back(o);} template <typename RET, typename... ARGS1, typename... ARGS2> RET change (Object*, RET (Object::*)(ARGS1...), ARGS2&&...); }; struct Object { int value; double rating; char letter; std::string str; Mediator& mediator; Object (int v, double r, char l, const std::string& s, Mediator& m) : value(v), rating(r), letter(l), str(s), mediator(m) {mediator.registerObject(this);} virtual void adjust (int, double, char, const std::string&) = 0; template <typename RET, typename... ARGS1, typename... ARGS2> RET change (RET (Object::*f)(ARGS1...), ARGS2&&... args) { return mediator.change(this, f, std::forward<ARGS2>(args)...); } }; struct A : Object { using Object::Object; virtual void adjust (int a, double b, char c, const std::string& s) override { std::cout << "Type A adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } }; struct B : Object { using Object::Object; virtual void adjust (int a, double b, char c, const std::string& s) override { std::cout << "Type B adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } }; struct C : Object { using Object::Object; virtual void adjust (int a, double b, char c, const std::string& s) override { std::cout << "Type C adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } }; template <typename RET, typename... ARGS1, typename... ARGS2> RET Mediator::change (Object* o, RET (Object::*f)(ARGS1...), ARGS2&&... args) { const std::tuple<ARGS2...> t(args...); for (Object* x : objects) (x->*f)(std::get<0>(t), o->rating, std::get<1>(t), o->str); } int main() { Mediator mediator; Object *a = new A(6, 1.2, 'a', "alan", mediator); Object *b = new B(2, 6.5, 'b', "bob", mediator); Object *c = new C(4, 0.8, 'c', "craig", mediator); c->change (&Object::adjust, 8, 'k'); } 

Output:

 Type A adjusted using values 8, 0.8, k, and craig. Type B adjusted using values 8, 0.8, k, and craig. Type C adjusted using values 8, 0.8, k, and craig. 

This is until I got my decision. It gives the same result, but the line is labeled // Here! - this is what I need to create automatically.

 #include <iostream> #include <string> #include <vector> #include <tuple> template <std::size_t...> struct index_sequence {}; template <std::size_t N, std::size_t... Is> struct make_index_sequence_helper : make_index_sequence_helper<N-1, N-1, Is...> {}; template <std::size_t... Is> struct make_index_sequence_helper<0, Is...> { using type = index_sequence<Is...>; }; template <std::size_t N> using make_index_sequence = typename make_index_sequence_helper<N>::type; struct Mediator { std::vector<struct Object*> objects; void registerObject (Object* o) {objects.emplace_back(o);} template <typename RET, typename... ARGS1, typename... ARGS2> RET change (Object*, RET (Object::*)(ARGS1...), ARGS2&&...); template <typename RET, typename... ARGS, std::size_t... Is> RET changeHelper (RET (Object::*)(ARGS...), const std::tuple<ARGS...>&, index_sequence<Is...>); }; struct Object { int value; double rating; char letter; std::string str; Mediator& mediator; Object (int v, double r, char l, const std::string& s, Mediator& m) : value(v), rating(r), letter(l), str(s), mediator(m) {mediator.registerObject(this);} virtual void adjust (int, double, char, const std::string&) = 0; template <typename RET, typename... ARGS1, typename... ARGS2> RET change (RET (Object::*f)(ARGS1...), ARGS2&&... args) { return mediator.change(this, f, std::forward<ARGS2>(args)...); } }; struct A : Object { using Object::Object; virtual void adjust (int a, double b, char c, const std::string& s) override { std::cout << "Type A adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } }; struct B : Object { using Object::Object; virtual void adjust (int a, double b, char c, const std::string& s) override { std::cout << "Type B adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } }; struct C : Object { using Object::Object; virtual void adjust (int a, double b, char c, const std::string& s) override { std::cout << "Type C adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } }; template <typename RET, typename... ARGS1, typename... ARGS2> RET Mediator::change (Object* o, RET (Object::*f)(ARGS1...), ARGS2&&... args) { const std::tuple<ARGS2...> t(args...); // Here! const std::tuple<ARGS1...> tuple(std::get<0>(t), o->rating, std::get<1>(t), o->str); changeHelper (f, tuple, make_index_sequence<sizeof...(ARGS1)>()); } template <typename RET, typename... ARGS, std::size_t... Is> RET Mediator::changeHelper (RET (Object::*f)(ARGS...), const std::tuple<ARGS...>& tuple, index_sequence<Is...>) { for (Object* x : objects) (x->*f) (std::get<Is>(tuple)...); } int main() { Mediator mediator; Object *a = new A(6, 1.2, 'a', "alan", mediator); Object *b = new B(2, 6.5, 'b', "bob", mediator); Object *c = new C(4, 0.8, 'c', "craig", mediator); c->change (&Object::adjust, 8, 'k'); } 

How to automatically generate a tuple

 const std::tuple<ARGS1...> tuple(std::get<0>(t), o->rating, std::get<1>(t), o->str); 

using something along the lines

 template <typename... ARGS1, typename... ARGS2> std::tuple<ARGS1...> extractTuple (Object* o, ARGS2&&... args); 

so that new versions of Mediator :: change will not be needed for different (perhaps many, if ARGS1 ... is large), the choice of ARGS2 ...? My current idea is to use a recursive helper method, std :: is_same, std :: tuple_cat, etc., but I have problems (I think we unpack ARGS2 ... when unpacking ARGS1 ... during type checking) .

+6
source share
3 answers

First, we need a tag and a series of functions to get values ​​from objects based on their types. Simple enough.

 template<class T> struct typetag {}; const int& get_type_from_class(const Object* o, typetag<int>) {return o->value;} const double& get_type_from_class(const Object* o, typetag<double>) {return o->rating;} const char& get_type_from_class(const Object* o, typetag<char>) {return o->letter;} const long& get_type_from_class(const Object* o, typetag<long>) {return o->tag;} 

The next part is that we need to get types from a list of parameters based on their types, and the first parameter returns by default if the parameters do not match. Also not insanely complicated. There is a recursive case of non-compliance, a recursive case of compliance and a case of last matching. Although this seems to have sufficient recursion, even the simplest optimizer should be able to integrate it into the optimal assembly. For reasons I don’t understand, they should be in that exact order.

 template<class T> const T& get_T_by_type(const T& def) {return def;} template<class T, class...pRest> const T& get_T_by_type(const T& def, const T& returnme, const pRest&...rest) {return returnme;} template<class T, class p0, class...pRest> const T& get_T_by_type(const T& def, const p0& discard, const pRest&...rest) {return get_T_by_type(def, rest...);} 

Finally, we call the function. For each ARGS1 we call get_T_by_type to get the same type of ARGS2 , and by default we use get_type_from_class to pass the existing value in the class.

 template <typename RET, typename... ARGS1, typename... ARGS2> void Mediator::change (Object* o, RET (Object::*f)(ARGS1...), const ARGS2&... args) { for (Object* x : objects) { (x->*f)( get_T_by_type(get_type_from_class(o, typetag<ARGS1>{}),args...) //pass all args2 ... //pass one of that for each args1 ); } } 

Note that I changed the return type to void , since you are delegating a call to several functions. Alternatively, you can return vector return results.

http://coliru.stacked-crooked.com/a/36afa072711b0655

+2
source

Ok, I have a first project. It still needs to be generalized by unpacking ARGS1 ... instead of how I did it below. But at least this first solution shows that the problem can probably be solved in its entirety.

 #include <iostream> #include <string> #include <vector> #include <tuple> template <std::size_t...> struct index_sequence {}; template <std::size_t N, std::size_t... Is> struct make_index_sequence_helper : make_index_sequence_helper<N-1, N-1, Is...> {}; template <std::size_t... Is> struct make_index_sequence_helper<0, Is...> { using type = index_sequence<Is...>; }; template <std::size_t N> using make_index_sequence = typename make_index_sequence_helper<N>::type; struct Mediator { std::vector<struct Object*> objects; void registerObject (Object* o) {objects.emplace_back(o);} template <typename RET, typename... ARGS1, typename... ARGS2> RET change (Object*, RET (Object::*)(ARGS1...), ARGS2&&...); template <typename RET, typename... ARGS, std::size_t... Is> RET changeHelper (RET (Object::*)(ARGS...), const std::tuple<ARGS...>&, index_sequence<Is...>); }; struct Object { int value; double rating; char letter; long tag; Mediator& mediator; Object (int v, double r, char l, long s, Mediator& m) : value(v), rating(r), letter(l), tag(s), mediator(m) {mediator.registerObject(this);} virtual void adjust (int, double, char, long) = 0; virtual void transform (char, double, int) = 0; template <typename RET, typename... ARGS1, typename... ARGS2> RET change (RET (Object::*f)(ARGS1...), ARGS2&&... args) { return mediator.change(this, f, std::forward<ARGS2>(args)...); } }; struct A : Object { using Object::Object; virtual void adjust (int a, double b, char c, long s) override { std::cout << "Type A adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } virtual void transform (char a, double b, int c) override { std::cout << "Type A transformed using values " << a << ", " << b << ", and " << c << "." << std::endl; } }; struct B : Object { using Object::Object; virtual void adjust (int a, double b, char c, long s) override { std::cout << "Type B adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } virtual void transform (char a, double b, int c) override { std::cout << "Type B transformed using values " << a << ", " << b << ", and " << c << "." << std::endl; } }; struct C : Object { using Object::Object; virtual void adjust (int a, double b, char c, long s) override { std::cout << "Type C adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } virtual void transform (char a, double b, int c) override { std::cout << "Type C transformed using values " << a << ", " << b << ", and " << c << "." << std::endl; } }; template <typename T, typename TUPLE> struct Concatenate; template <typename FIRST, typename ...REST> struct Concatenate<FIRST, std::tuple<REST...>> { using type = typename std::tuple<FIRST, REST...>; }; template <typename HEAD, typename TUPLE> typename Concatenate<HEAD, TUPLE>::type nextTuple (Object* o, const TUPLE& tuple) { if (std::is_same<HEAD, int>::value) return std::tuple_cat (tuple, std::tuple<int>(o->value)); else if (std::is_same<HEAD, double>::value) return std::tuple_cat (tuple, std::tuple<double>(o->rating)); else if (std::is_same<HEAD, char>::value) return std::tuple_cat (tuple, std::tuple<char>(o->letter)); else if (std::is_same<HEAD, long>::value) return std::tuple_cat (tuple, std::tuple<long>(o->tag)); } template <typename HEAD, typename TUPLE, typename FIRST, typename... REST> typename Concatenate<HEAD, TUPLE>::type nextTuple (Object* o, const TUPLE& tuple, FIRST first, REST... rest) { if (std::is_same<HEAD, FIRST>::value) return std::tuple_cat (tuple, std::tuple<FIRST>(first)); return nextTuple<HEAD, TUPLE, REST...> (o, tuple, rest...); } template <typename RET, typename... ARGS1, typename... ARGS2> std::tuple<ARGS1...> extractTuple (Object* o, RET (Object::*)(ARGS1...), ARGS2&&... args) { // Function pointer parameter needed to maintain ARGS1..., else it will become an empty pack. std::tuple<> t0; const auto t1 = nextTuple<int> (o, t0, args...); // In general, unpack ARGS1... const auto t2 = nextTuple<double> (o, t1, args...); const auto t3 = nextTuple<char> (o, t2, args...); return nextTuple<long> (o, t3, args...); } template <typename RET, typename... ARGS1, typename... ARGS2> RET Mediator::change (Object* o, RET (Object::*f)(ARGS1...), ARGS2&&... args) { const std::tuple<ARGS1...> tuple = extractTuple (o, f, args...); // The key function. changeHelper (f, tuple, make_index_sequence<sizeof...(ARGS1)>()); } template <typename RET, typename... ARGS, std::size_t... Is> RET Mediator::changeHelper (RET (Object::*f)(ARGS...), const std::tuple<ARGS...>& tuple, index_sequence<Is...>) { for (Object* x : objects) (x->*f) (std::get<Is>(tuple)...); } int main() { Mediator mediator; Object *a = new A(6, 1.2, 'a', 1111, mediator); Object *b = new B(2, 6.5, 'b', 2222, mediator); Object *c = new C(4, 0.8, 'c', 3333, mediator); c->change (&Object::adjust, 8, 'k'); // c->change (&Object::transform, 'z', 4); // This does not work though. } 

Output:

 Type A adjusted using values 8, 0, k, and 3333. Type B adjusted using values 8, 0, k, and 3333. Type C adjusted using values 8, 0, k, and 3333. 

For some reason there were problems with std :: string, so I replaced the 4th parameter with a long one. Thus, this decision still needs to be clarified. I also introduced a new transform member function to show that the string c->change (&Object::transform, 'z', 4); in main () does NOT work (and does not work in the Mooing Duck solution), and therefore this solution needs more generalization, recursion with ARGS1 ... perhaps to be complete. In my solution above, only one ARGS1 ... is processed in the form (int, double, char, long).

I suspect that the Mooing Duck solution can also be generalized to handle any new member function of an object passed to Mediator :: change.

UPDATE: Ok, I replaced extractTuple with

 template <typename TUPLE, typename... ARGS2> TUPLE extractTuple (Object*, const TUPLE& tuple, ARGS2&&...) {return tuple;} template <typename TUPLE, typename FIRST, typename... REST, typename... ARGS2> auto extractTuple (Object* o, const TUPLE& current, ARGS2&&... args) -> decltype (extractTuple<typename Concatenate<FIRST, TUPLE>::type, REST...> (o, nextTuple<FIRST> (o, current, args...), args...)) { const typename Concatenate<FIRST, TUPLE>::type next = nextTuple<FIRST> (o, current, args...); return extractTuple<typename Concatenate<FIRST, TUPLE>::type, REST...> (o, next, args...); } 

and I think this generalizes the above solution by unpacking ARGS1 ... Here is my new code:

 #include <iostream> #include <string> #include <vector> #include <tuple> template <std::size_t...> struct index_sequence {}; template <std::size_t N, std::size_t... Is> struct make_index_sequence_helper : make_index_sequence_helper<N-1, N-1, Is...> {}; template <std::size_t... Is> struct make_index_sequence_helper<0, Is...> { using type = index_sequence<Is...>; }; template <std::size_t N> using make_index_sequence = typename make_index_sequence_helper<N>::type; struct Mediator { std::vector<struct Object*> objects; void registerObject (Object* o) {objects.emplace_back(o);} template <typename RET, typename... ARGS1, typename... ARGS2> RET change (Object*, RET (Object::*)(ARGS1...), ARGS2&&...); template <typename RET, typename... ARGS, std::size_t... Is> RET changeHelper (RET (Object::*)(ARGS...), const std::tuple<ARGS...>&, index_sequence<Is...>); }; struct Object { int value; double rating; char letter; long tag; Mediator& mediator; Object (int v, double r, char l, long s, Mediator& m) : value(v), rating(r), letter(l), tag(s), mediator(m) {mediator.registerObject(this);} virtual void adjust (int, double, char, long) = 0; virtual void transform (char, double, int) = 0; template <typename RET, typename... ARGS1, typename... ARGS2> RET change (RET (Object::*f)(ARGS1...), ARGS2&&... args) { return mediator.change(this, f, std::forward<ARGS2>(args)...); } }; struct A : Object { using Object::Object; virtual void adjust (int a, double b, char c, long s) override { std::cout << "Type A adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } virtual void transform (char a, double b, int c) override { std::cout << "Type A transformed using values " << a << ", " << b << ", and " << c << "." << std::endl; } }; struct B : Object { using Object::Object; virtual void adjust (int a, double b, char c, long s) override { std::cout << "Type B adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } virtual void transform (char a, double b, int c) override { std::cout << "Type B transformed using values " << a << ", " << b << ", and " << c << "." << std::endl; } }; struct C : Object { using Object::Object; virtual void adjust (int a, double b, char c, long s) override { std::cout << "Type C adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } virtual void transform (char a, double b, int c) override { std::cout << "Type C transformed using values " << a << ", " << b << ", and " << c << "." << std::endl; } }; template <typename T, typename TUPLE> struct Concatenate; template <typename FIRST, typename ...REST> struct Concatenate<FIRST, std::tuple<REST...>> { using type = typename std::tuple<FIRST, REST...>; }; template <typename HEAD, typename TUPLE> typename Concatenate<HEAD, TUPLE>::type nextTuple (Object* o, const TUPLE& tuple) { if (std::is_same<HEAD, int>::value) // Using overload from some new class can probably handle all these cases better. return std::tuple_cat (tuple, std::tuple<int>(o->value)); else if (std::is_same<HEAD, double>::value) return std::tuple_cat (tuple, std::tuple<double>(o->rating)); else if (std::is_same<HEAD, char>::value) return std::tuple_cat (tuple, std::tuple<char>(o->letter)); else if (std::is_same<HEAD, long>::value) return std::tuple_cat (tuple, std::tuple<long>(o->tag)); } template <typename HEAD, typename TUPLE, typename FIRST, typename... REST> typename Concatenate<HEAD, TUPLE>::type nextTuple (Object* o, const TUPLE& tuple, FIRST first, REST... rest) { if (std::is_same<HEAD, FIRST>::value) return std::tuple_cat (tuple, std::tuple<FIRST>(first)); return nextTuple<HEAD, TUPLE, REST...> (o, tuple, rest...); } template <typename TUPLE, typename... ARGS2> TUPLE extractTuple (Object*, const TUPLE& tuple, ARGS2&&...) {return tuple;} // *** The change template <typename TUPLE, typename FIRST, typename... REST, typename... ARGS2> auto extractTuple (Object* o, const TUPLE& current, ARGS2&&... args) -> decltype (extractTuple<typename Concatenate<FIRST, TUPLE>::type, REST...> (o, nextTuple<FIRST> (o, current, args...), args...)) { const typename Concatenate<FIRST, TUPLE>::type next = nextTuple<FIRST> (o, current, args...); return extractTuple<typename Concatenate<FIRST, TUPLE>::type, REST...> (o, next, args...); } template <typename RET, typename... ARGS1, typename... ARGS2> RET Mediator::change (Object* o, RET (Object::*f)(ARGS1...), ARGS2&&... args) { const std::tuple<ARGS1...> tuple = extractTuple<std::tuple<>, ARGS1...> (o, std::tuple<>(), args...); // The key function. changeHelper (f, tuple, make_index_sequence<sizeof...(ARGS1)>()); } template <typename RET, typename... ARGS, std::size_t... Is> RET Mediator::changeHelper (RET (Object::*f)(ARGS...), const std::tuple<ARGS...>& tuple, index_sequence<Is...>) { for (Object* x : objects) (x->*f) (std::get<Is>(tuple)...); } int main() { Mediator mediator; Object *a = new A(6, 1.2, 'a', 1111, mediator); Object *b = new B(2, 6.5, 'b', 2222, mediator); Object *c = new C(4, 0.8, 'c', 3333, mediator); c->change (&Object::adjust, 8, 'k'); c->change (&Object::transform, 'z', 4); } 

Note that c->change (&Object::transform, 'z', 4); now located in main (). But my GCC 4.8.1 seems to be listening and cannot handle the ad

 template <typename TUPLE, typename FIRST, typename... REST, typename... ARGS2> auto extractTuple (Object* o, const TUPLE& current, ARGS2&&... args) -> decltype (extractTuple<typename Concatenate<FIRST, TUPLE>::type, REST...> (o, nextTuple<FIRST> (o, current, args...), args...)) { 

resulting in an "internal compiler error". Perhaps someone with a later compiler with C ++ 14 can check if this is a legal expression or not? I don't have C ++ 14.

0
source

This answer is based on the original Mooing Duck answer, which handled only a special case. I added about doubling the amount of code to summarize its answer using tuples. However, his new general solution above is clearly higher.

 #include <iostream> #include <string> #include <vector> #include <tuple> template <std::size_t...> struct index_sequence {}; template <std::size_t N, std::size_t... Is> struct make_index_sequence_helper : make_index_sequence_helper<N-1, N-1, Is...> {}; template <std::size_t... Is> struct make_index_sequence_helper<0, Is...> { using type = index_sequence<Is...>; }; template <std::size_t N> using make_index_sequence = typename make_index_sequence_helper<N>::type; struct Mediator { std::vector<struct Object*> objects; void registerObject (Object* o) {objects.emplace_back(o);} template <typename RET, typename... ARGS1, typename... ARGS2> RET change (Object*, RET (Object::*)(ARGS1...), ARGS2&&...); template <typename RET, typename... ARGS, std::size_t... Is> RET changeHelper (RET (Object::*)(ARGS...), const std::tuple<ARGS...>&, index_sequence<Is...>); }; struct Object { int value; double rating; char letter; long tag; Mediator& mediator; Object (int v, double r, char l, long s, Mediator& m) : value(v), rating(r), letter(l), tag(s), mediator(m) {mediator.registerObject(this);} virtual void adjust (int, double, char, long) = 0; virtual void transform (char, double, int) = 0; template <typename RET, typename... ARGS1, typename... ARGS2> RET change (RET (Object::*f)(ARGS1...), ARGS2&&... args) { return mediator.change(this, f, std::forward<ARGS2>(args)...); } }; struct A : Object { using Object::Object; virtual void adjust (int a, double b, char c, long s) override { std::cout << "Type A adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } virtual void transform (char a, double b, int c) override { std::cout << "Type A transformed using values " << a << ", " << b << ", and " << c << "." << std::endl; } }; struct B : Object { using Object::Object; virtual void adjust (int a, double b, char c, long s) override { std::cout << "Type B adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } virtual void transform (char a, double b, int c) override { std::cout << "Type B transformed using values " << a << ", " << b << ", and " << c << "." << std::endl; } }; struct C : Object { using Object::Object; virtual void adjust (int a, double b, char c, long s) override { std::cout << "Type C adjusted using values " << a << ", " << b << ", " << c << ", and " << s << "." << std::endl; } virtual void transform (char a, double b, int c) override { std::cout << "Type C transformed using values " << a << ", " << b << ", and " << c << "." << std::endl; } }; template <typename T, typename TUPLE> struct Concatenate; template <typename FIRST, typename ...REST> struct Concatenate<FIRST, std::tuple<REST...>> { using type = typename std::tuple<REST..., FIRST>; // This time, we must concatenate at the back else 'extractTuple<std::tuple<>, ARGS1...>(t, std::tuple<>())' below will be in reverse! }; struct NamedObjectChangeParameters { int value; double rating; char letter; long tag; explicit NamedObjectChangeParameters (const Object& o) : value(o.value), rating(o.rating), letter(o.letter), tag(o.tag) {} // change overloads for Mediator::change. void change (int a) {value = a;} void change (double b) {rating = b;} void change (char c) {letter = c;} void change (long d) {tag = d;} template <typename FIRST, typename... REST> void change (const FIRST& first, const REST&... rest) { change (first); change (rest...); } // nextTuple overloads for the important extractTuple function. template <typename TUPLE> typename Concatenate<int, TUPLE>::type nextTuple (int, const TUPLE& tuple) {return std::tuple_cat (tuple, std::tuple<int>(value));} template <typename TUPLE> typename Concatenate<double, TUPLE>::type nextTuple (double, const TUPLE& tuple) {return std::tuple_cat (tuple, std::tuple<int>(rating));} template <typename TUPLE> typename Concatenate<char, TUPLE>::type nextTuple (char, const TUPLE& tuple) {return std::tuple_cat (tuple, std::tuple<int>(letter));} template <typename TUPLE> typename Concatenate<long, TUPLE>::type nextTuple (long, const TUPLE& tuple) {return std::tuple_cat (tuple, std::tuple<int>(tag));} }; template <typename TUPLE> TUPLE extractTuple (NamedObjectChangeParameters&, const TUPLE& tuple) {return tuple;} template <typename TUPLE, typename FIRST, typename... REST> auto extractTuple (NamedObjectChangeParameters& t, const TUPLE& current) -> decltype (extractTuple<typename Concatenate<FIRST, TUPLE>::type, REST...> (t, t.nextTuple<TUPLE> (FIRST(), current))) { const typename Concatenate<FIRST, TUPLE>::type next = t.nextTuple<TUPLE> (FIRST(), current); // nextTuple<TUPLE> is an overloaded function of NamedObjectChangeParameters that creates the correct type based on what type FIRST is. return extractTuple<typename Concatenate<FIRST, TUPLE>::type, REST...> (t, next); } template <typename RET, typename... ARGS1, typename... ARGS2> RET Mediator::change (Object* o, RET (Object::*f)(ARGS1...), ARGS2&&... args) { NamedObjectChangeParameters t(*o); t.change(args...); changeHelper (f, extractTuple<std::tuple<>, ARGS1...>(t, std::tuple<>()), make_index_sequence<sizeof...(ARGS1)>()); } template <typename RET, typename... ARGS, std::size_t... Is> RET Mediator::changeHelper (RET (Object::*f)(ARGS...), const std::tuple<ARGS...>& tuple, index_sequence<Is...>) { for (Object* x : objects) (x->*f) (std::get<Is>(tuple)...); } int main() { Mediator mediator; Object *a = new A(6, 1.2, 'a', 1111, mediator); Object *b = new B(2, 6.5, 'b', 2222, mediator); Object *c = new C(4, 0.8, 'c', 3333, mediator); c->change (&Object::adjust, 8, 'k'); c->change (&Object::transform, 'z', 4); } 

Output:

 Type A adjusted using values 8, 0, k, and 3333. Type B adjusted using values 8, 0, k, and 3333. Type C adjusted using values 8, 0, k, and 3333. Type A transformed using values z, 0, and 4. Type B transformed using values z, 0, and 4. Type C transformed using values z, 0, and 4. 
0
source

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


All Articles