mml::make_multimethod(f1, f2,..., fn)
void f(int){} void f(double){} void f(char, void*){}
auto of = f; // f
struct f { void operator()(int) const {} void operator()(double) const {} void operator()(char, void*) const {} }; auto of = f(); // , of ,
struct game_object { virtual ~game_object() { } }; struct space_ship : game_object { }; struct space_station : game_object { }; struct asteroid : game_object { };
vector<game_object*>& get_obj_pointers() { static space_ship ship; static asteroid ast; static space_station station; static vector<game_object*> objs; if (objs.empty()) { objs.push_back(&ship); objs.push_back(&ast); objs.push_back(&station); } return objs; }
const char* collide_go_go(game_object*, game_object*) { return "Unsupported colliding!"; } const char* collide_sh_sh(space_ship*, space_ship*) { return "Space ship collides with space ship"; } const char* collide_sh_as(space_ship*, asteroid*) { return "Space ship collides with asteroid"; } const char* collide_as_sh(asteroid*, space_ship*) { return "Asteroid collides with space ship"; } const char* collide_as_as(asteroid*, asteroid*) { return "Asteroid collides with asteroid"; }
#include <mml/generation/make_multimethod.hpp> auto collide = make_multimethod( collide_go_go , collide_sh_sh , collide_sh_as , collide_as_sh , collide_as_as );
auto& objs = get_obj_pointers(); for (size_t i = 0; i < objs.size(); ++i) for (size_t j = 0; j < objs.size(); ++j) cout << '\t' << collide(objs[i], objs[j]) << endl;
Space ship collides with space ship Space ship collides with asteroid Asteroid collides with space ship Asteroid collides with asteroid
inline const char* collide(game_object* obj1, game_object* obj2) { if (space_ship* sh1 = dynamic_cast<space_ship*>(obj1)) if (space_ship* sh2 = dynamic_cast<space_ship*>(obj2)) return collide_sh_sh(sh1, sh2); else if (asteroid* as2 = dynamic_cast<asteroid*>(obj2)) return collide_sh_as(sh1, as2); else return collide_go_go(sh1, obj2); else if (asteroid* as1 = dynamic_cast<asteroid*>(obj1)) if (space_ship* sh2 = dynamic_cast<space_ship*>(obj2)) return collide_as_sh(as1, sh2); else if (asteroid* as2 = dynamic_cast<asteroid*>(obj2)) return collide_as_as(as1, as2); else return collide_go_go(as1, obj2); else if (space_ship* sh2 = dynamic_cast<space_ship*>(obj2)) return collide_go_go(obj1, sh2); else if (asteroid* as2 = dynamic_cast<asteroid*>(obj2)) return collide_go_go(obj1, as2); else return collide_go_go(obj1, obj2); }
boost::ptr_vector<game_object>& get_objs_refs() { static boost::ptr_vector<game_object> objs; if (objs.empty()) { objs.push_back(new space_ship); objs.push_back(new asteroid); objs.push_back(new space_station); } return objs; }
const char* collide_ref_go_go(game_object&, game_object&) { return "Unsupported colliding!"; } const char* collide_ref_sh_sh(space_ship&, space_ship&) { return "Space ship collides with space ship"; } const char* collide_ref_sh_as(space_ship&, asteroid&) { return "Space ship collides with asteroid"; } const char* collide_ref_as_sh(asteroid&, space_ship&) { return "Asteroid collides with space ship"; } const char* collide_ref_as_as(asteroid&, asteroid&) { return "Asteroid collides with asteroid"; }
template <typename F, typename Objs> void collide_tester(F collide, Objs& objs) { for (size_t i = 0; i < 2; ++i) for (size_t j = 0; j < 2; ++j) cout << '\t' << collide(objs[i], objs[j]) << endl; }
#include <mml/generation/make_ref_multimethod.hpp> collide_tester( make_ref_multimethod( collide_ref_go_go , collide_ref_sh_sh , collide_ref_sh_as , collide_ref_as_sh , collide_ref_as_as ) , get_objs_refs() );
Space ship collides with space ship Space ship collides with asteroid Asteroid collides with space ship Asteroid collides with asteroid
struct collider_sh_as { const char* operator()(space_ship*, asteroid*) const { return "Space ship collides with asteroid"; } }; collide_tester( make_multimethod( collide_go_go , collide_sh_sh , collider_sh_as() , collide_as_sh , collide_as_as ) , get_obj_pointers() );
struct collider_sh_as { typedef const char* signature(space_ship*, asteroid*); ... }
struct collider_sh_as { typedef const char* result_type; typedef space_ship* arg1_type; typedef asteroid* arg2_type; ... }
struct collider_sh_as { typedef const char* result_type; typedef space_ship* first_argument_type; typedef asteroid* second_argument_type; ... }
struct collider_sh_as : std::binary_function<space_ship*, asteroid*, result_type> { ... }
// , , const char* collide_void() { return "Nothing collides?!"; } // , const char* collide_go(game_object*) { return "Unsupported colliding!"; } const char* collide_sh(space_ship*) { return "Space ship collides with what?!"; } const char* collide_as(asteroid*) { return "Asteroid collides with what?!"; } const char* collide_go_go_go(game_object*, game_object*, game_object*) { return "Unsupported colliding!"; } const char* collide_sh_as_as(space_ship*, asteroid*, asteroid*) { return "Space ship collides with two asteroids"; } const char* collide_sh_as_st(space_ship*, asteroid*, space_station*) { return "Space ship collides with asteroid and space_station"; }
template <typename F, typename Objs> void collide_tester_var_arg(F collide, Objs& objs) { // cout << '\t' << collide() << endl; // 1 cout << '\t' << collide(objs[0]) << endl; cout << '\t' << collide(objs[1]) << endl; // 2 cout << '\t' << collide(objs[0], objs[0]) << endl; cout << '\t' << collide(objs[0], objs[1]) << endl; // 3 cout << '\t' << collide(objs[0], objs[1], objs[1]) << endl; cout << '\t' << collide(objs[0], objs[1], objs[2]) << endl; }
collide_tester_var_arg( make_multimethod( collide_go_go , collide_sh_sh , collide_sh_as , collide_void , collide_go , collide_sh , collide_as , collide_go_go_go , collide_sh_as_as , collide_sh_as_st ) , get_obj_pointers() );
Nothing collides Space ship collides with what?! Asteroid collides with what?! Space ship collides with space ship Space ship collides with asteroid Space ship collides with two asteroids Space ship collides with asteroid and space_station
// collide() inline const char* collide() { return collide_void(); } // ! // collide(objs[0]) // collide(objs[1]) inline const char* collide(game_object* obj) { if (space_ship* sh = dynamic_cast<space_ship*>(obj)) return collide_sh(sh); else if (asteroid* as = dynamic_cast<asteroid*>(obj)) return collide_as(as); else return collide_go(obj); } // : // min 1 cast // max 2 casts // collide(objs[0], objs[0]) // collide(objs[0], objs[1]) // , : inline const char* collide(game_object* obj1, game_object* obj2) {...} // collide(objs[0], objs[1], objs[1]) // collide(objs[0], objs[1], objs[2]) inline const char* collide(game_object* obj1, game_object* obj2, game_object* obj3) { if (space_ship* sh1 = dynamic_cast<space_ship*>(obj1)) if (space_ship* sh2 = dynamic_cast<space_ship*>(obj2)) if (asteroid* as3 = dynamic_cast<asteroid*>(obj3)) return collide_go_go_go(sh1, sh2, as3); else if (space_station* st3 = dynamic_cast<space_station*>(obj3)) return collide_go_go_go(sh1, sh2, st3); else return collide_go_go_go(sh1, sh2, obj3); else if (asteroid* as2 = dynamic_cast<asteroid*>(obj2)) if (asteroid* as3 = dynamic_cast<asteroid*>(obj3)) return collide_sh_as_as(sh1, as2, as3); else if (space_station* st3 = dynamic_cast<space_station*>(obj3)) return collide_sh_as_st(sh1, as2, st3); else return collide_go_go_go(sh1, as2, obj3); else if (asteroid* as3 = dynamic_cast<asteroid*>(obj3)) return collide_go_go_go(sh1, obj2, as3); else if (space_station* st3 = dynamic_cast<space_station*>(obj3)) return collide_go_go_go(sh1, obj2, st3); else return collide_go_go_go(sh1, obj2, obj3); else if (asteroid* as1 = dynamic_cast<asteroid*>(obj1)) if (space_ship* sh2 = dynamic_cast<space_ship*>(obj2)) if (asteroid* as3 = dynamic_cast<asteroid*>(obj3)) return collide_go_go_go(as1, sh2, as3); else if (space_station* st3 = dynamic_cast<space_station*>(obj3)) return collide_go_go_go(as1, sh2, st3); else return collide_go_go_go(as1, sh2, obj3); else if (asteroid* as2 = dynamic_cast<asteroid*>(obj2)) if (asteroid* as3 = dynamic_cast<asteroid*>(obj3)) return collide_go_go_go(as1, as2, as3); else if (space_station* st3 = dynamic_cast<space_station*>(obj3)) return collide_go_go_go(as1, as2, st3); else return collide_go_go_go(as1, as2, obj3); else if (asteroid* as3 = dynamic_cast<asteroid*>(obj3)) return collide_go_go_go(as1, obj2, as3); else if (space_station* st3 = dynamic_cast<space_station*>(obj3)) return collide_go_go_go(as1, obj2, st3); else return collide_go_go_go(as1, obj2, obj3); else if (space_ship* sh2 = dynamic_cast<space_ship*>(obj2)) if (asteroid* as3 = dynamic_cast<asteroid*>(obj3)) return collide_go_go_go(obj1, sh2, as3); else if (space_station* st3 = dynamic_cast<space_station*>(obj3)) return collide_go_go_go(obj1, sh2, st3); else return collide_go_go_go(obj1, sh2, obj3); else if (asteroid* as2 = dynamic_cast<asteroid*>(obj2)) if (asteroid* as3 = dynamic_cast<asteroid*>(obj3)) return collide_go_go_go(obj1, as2, as3); else if (space_station* st3 = dynamic_cast<space_station*>(obj3)) return collide_go_go_go(obj1, as2, st3); else return collide_go_go_go(obj1, as2, obj3); else if (asteroid* as3 = dynamic_cast<asteroid*>(obj3)) return collide_go_go_go(obj1, obj2, as3); else if (space_station* st3 = dynamic_cast<space_station*>(obj3)) return collide_go_go_go(obj1, obj2, st3); else return collide_go_go_go(obj1, obj2, obj3); } // : // min 3 casts // max 6 casts
const char* collide_go_go_int(game_object*, game_object*, int) { return "Unsupported colliding with extra int parameter!"; } const char* collide_sh_as_int(space_ship*, asteroid*, int) { return "Space ship collides with asteroid with extra int parameter"; }
template <typename F, typename Objs> void collide_tester_non_polymorphic_arg(F collide, Objs& objs) { cout << '\t' << collide(objs[0], objs[1]) << endl; cout << '\t' << collide(objs[0], objs[1], objs[2]) << endl; cout << '\t' << collide(objs[0], objs[1], 1) << endl; }
collide_tester_non_polymorphic_arg( make_multimethod( collide_go_go , collide_sh_sh , collide_sh_as , collide_as_sh , collide_as_as , collide_go_go_go , collide_sh_as_st , collide_sh_as_as , collide_go_go_int , collide_sh_as_int ) , get_obj_pointers() );
Space ship collides with asteroid Space ship collides with asteroid and space_station Space ship collides with asteroid with extra int parameter
// collide(objs[0], objs[1], 1) inline const char* collide(game_object* obj1, game_object* obj2, int n) { if (space_ship* sh1 = dynamic_cast<space_ship*>(obj1)) if (space_ship* sh2 = dynamic_cast<space_ship*>(obj2)) return collide_go_go_int(sh1, sh2, n); else if (asteroid* as2 = dynamic_cast<asteroid*>(obj2)) return collide_sh_as_int(sh1, as2, n); else return collide_go_go_int(sh1, obj2, n); else if (asteroid* as1 = dynamic_cast<asteroid*>(obj1)) if (space_ship* sh2 = dynamic_cast<space_ship*>(obj2)) return collide_go_go_int(as1, sh2, n); else if (asteroid* as2 = dynamic_cast<asteroid*>(obj2)) return collide_go_go_int(as1, as2, n); else return collide_go_go_int(as1, obj2, n); else if (space_ship* sh2 = dynamic_cast<space_ship*>(obj2)) return collide_go_go_int(obj1, sh2, n); else if (asteroid* as2 = dynamic_cast<asteroid*>(obj2)) return collide_go_go_int(obj1, as2, n); else return collide_go_go_int(obj1, obj2, n); } // : // min 2 casts // max 4 casts
const char* collide_go_cvgo(game_object*, const volatile game_object*) { return "Unsupported colliding!"; } const char* collide_sh_cas(space_ship*, const asteroid*) { return "Space ship collides with const asteroid"; } const char* collide_sh_vas(space_ship*, volatile asteroid*) { return "Space ship collides with volatile asteroid"; } const char* collide_sh_cvas(space_ship*, const volatile asteroid*) { return "Space ship collides with const volatile asteroid"; } template <typename F, typename Objs> void collide_tester_cv(F collide, Objs& objs) { game_object* object = objs[1]; const game_object* c_object = objs[1]; const volatile game_object* cv_object = objs[1]; cout << '\t' << collide(objs[0], object) << endl; cout << '\t' << collide(objs[0], c_object) << endl; cout << '\t' << collide(objs[0], cv_object) << endl; } collide_tester_cv( make_multimethod( collide_sh_as , collide_go_cvgo , collide_sh_cas , collide_sh_vas , collide_sh_cvas ) , get_obj_pointers() ); }
Space ship collides with asteroid Space ship collides with const asteroid Space ship collides with const volatile asteroid
template <typename F, typename Objs> void collide_tester_compile_time_optim(F collide, Objs& objs) { space_ship ship; asteroid ast; cout << '\t' << collide(objs[0], &ast) << endl; cout << '\t' << collide(&ship, &ast) << endl; } collide_tester_compile_time_optim( make_multimethod( collide_go_go , collide_sh_sh , collide_sh_as , collide_as_sh , collide_as_as ) , get_obj_pointers() );
Space ship collides with asteroid Space ship collides with asteroid
// collide(objs[0], &ast) inline const char* collide(game_object* obj1, asteroid* as2) { if (space_ship* sh1 = dynamic_cast<space_ship*>(obj1)) return collide_sh_as(sh1, as2); else if (asteroid* as1 = dynamic_cast<asteroid*>(obj1)) return collide_as_as(as1, as2); else return collide_go_go(obj1, as2); } // : // min 1 cast // max 2 casts // collide(&ship, &ast) inline const char* collide(space_ship* sh1, asteroid* as2) { return collide_sh_as(sh1, as2); } // !
#include <mml/casting/sp_dynamic_caster.hpp> const char* sp_collide_go_go(game_object*, boost::shared_ptr<game_object>) { return "Unsupported colliding!"; } const char* sp_collide_sh_sh(space_ship*, boost::shared_ptr<space_ship>) { return "Space ship collides with smart_ptr space ship"; } struct sp_collider_sh_as { const char* operator()(space_ship*, boost::shared_ptr<asteroid>) const { return "Space ship collides with smart_ptr asteroid"; } }; template <typename F, typename Objs> void sp_collide_tester(F collide, Objs& objs) { boost::shared_ptr<game_object> obj1(new space_ship); boost::shared_ptr<game_object> obj2(new asteroid); cout << '\t' << collide(objs[0], obj1) << endl; cout << '\t' << collide(objs[0], obj2) << endl; } sp_collide_tester( make_multimethod( sp_collide_go_go , sp_collide_sh_sh , sp_collider_sh_as() ) , get_obj_pointers() );
Space ship collides with smart_ptr space ship Space ship collides with smart_ptr asteroid
// collide(objs[0], obj1) // collide(objs[0], obj2) inline const char* collide(game_object* obj1, const boost::shared_ptr<game_object>& sp_obj2) { if (space_ship* sh1 = dynamic_cast<space_ship*>(obj1)) if (boost::shared_ptr<space_ship> sp_sh2 = boost::shared_dynamic_cast<space_ship>(sp_obj2)) return sp_collide_sh_sh(sh1, sp_sh2); else if (boost::shared_ptr<asteroid> sp_as2 = boost::shared_dynamic_cast<asteroid>(sp_obj2)) return sp_collider_sh_as()(sh1, sp_as2); else return sp_collide_go_go(obj1, sp_obj2); else if (boost::shared_ptr<space_ship> sp_sh2 = boost::shared_dynamic_cast<space_ship>(sp_obj2)) return sp_collide_go_go(obj1, sp_sh2); else if (boost::shared_ptr<asteroid> sp_as2 = boost::shared_dynamic_cast<asteroid>(sp_obj2)) return sp_collide_go_go(obj1, sp_as2); else return sp_collide_go_go(obj1, sp_obj2); } // : // min 2 casts // max 3 casts
Source: https://habr.com/ru/post/155515/
All Articles