ãã«ãã¡ã½ãã4 対æ°æéç·¨
ãã«ãã¡ã½ãã3 åã¾ããæ¹è¯ç·¨ã®ç¶ãã§ãã
basic_dispatcher
flat_mapã使ã
RTTI(å®è¡æåæ
å ±)ã¨ãtype_index(typeinfoãæ¯è¼ã§ããããã«ã©ããããå)ã®2ã¤ããããã¨ã«ãããå
¨ã¦ã®åã«å¯¾ãã¦(ãã¡ããåçãªåãå«ã¿ã¾ã)ãé åºé¢ä¿ãæã¤ãã¨ãåºæ¥ã¾ããã¤ã¾ããå
¨ã¦ã®åããã¼ã¨ãã¦äºåæ¨æ¢ç´¢ãã§ããã¨ãããã¨ã§ãã
type_indexããã¼ã¨ããmapped_typeããã£ã¹ããããããé¢æ°ã¸ã®ãã¤ã³ã¿ã«ãããã¨ã§ã対æ°æéã§é¢æ°ããã£ã¹ããããããã¨ãåºæ¥ã¾ããstd::mapã使ãããã¨ããã§ãããstd::mapã¯æéçã«ã空éçã«ããªã¼ãã¼ãããã大ããã§ããã½ã¼ãæ¸ã¿vectorã使ããã¨ã§å¹çããäºåæ¢ç´¢ãè¡ããã¨ãåºæ¥ã¾ããmapãããã½ã¼ãæ¸ã¿vectorã®ã»ããå¹çãè¯ããªããã©ããã¯ãæ¿å
¥é »åº¦ããã¢ã¯ã»ã¹é »åº¦ãå¤ãå ´åæå¹ã«ãªãã¾ããä»åã¯æåã ãè¦ç´ ã®æ¿å
¥ãè¡ããå¾ã¯é¢æ°ãå¼ã³åºãã ãã§ãã®ã§è©²å½ãã¾ãã
ã½ã¼ãæ¸ã¿vectorã¨ãã¦mapã¨åãã¤ã³ã¿ã¼ãã§ã¤ã¹ã«ãªã£ã¦ããã³ã³ãããboostã«ããã¾ããboost::container::flat_mapã§ããããã使ã£ã¦ããã¾ãããã®ãã£ã¹ãããã£ãåºæ¬ã¨ãã¦ãä»å¾ã®ãã£ã¹ãããã£ãèãã¦ããã®ã§basic_dispatcherã¨å¼ã¶ãã¨ã«ãã¾ãã
template < class BaseLhs, class BaseRhs = BaseLhs, class Result = void, class CallBack = Result(*)(BaseLhs&, BaseRhs&) > class basic_dispatcher { #ifdef _MSC_VER using map_type = std::map<std::pair<std::type_index, std::type_index>, CallBack>; #else using map_type = boost::container::flat_map<std::type_index, std::type_index>, CallBack>; #endif using key_type = typename map_type::key_type; using mapped_type = typename map_type::mapped_type; map_type callback_; ...
Visual C++ 12.0ã§ã¯ãªããflat_mapã使ãã¨ã³ã³ãã¤ã«ã¨ã©ã¼ãåºãã®ã§VC++ã ãã¯std::mapã使ç¨ãã¦ãã¾ãã(gcc, clangã§ã¯ç¡åé¡)
std::pairã¯è¦ç´ ã®åãæ¯è¼å¯è½ãªã¨ããæ¯è¼ãããã¨ãåºæ¥ã¾ãããã£ã¦ãã¼ã®åã®std::pair<std::type_index, std::type_index>ã¯æ¯è¼å¯è½ãªåã¨ãªã£ã¦ãã¾ããpairã®firstã¯ãã£ã¹ãããããé¢æ°ã®å·¦è¾ºã®åã§ãsecondã¯ãã£ã¹ãããããå³è¾ºã®åã¨ãªãã¾ãã*1
ç»é²ããaddé¢æ°ã¨å¼ã³åºããããgoé¢æ°ã¯ä»¥ä¸ã®ããã«ãªãã¾ãã
... public: template <class SomeLhs, class SomeRhs> void add(CallBack func) { key_type const key(typeid(SomeLhs), typeid(SomeRhs)); callback_[key] = func; } Result go(BaseLhs& lhs, BaseRhs& rhs) { auto i = callback_.find(key_type(typeid(lhs), typeid(rhs))); if (i == callback_.end()) { throw std::runtime_error("é¢æ°ãè¦ã¤ããã¾ãã"); } return (i->second)(lhs, rhs); } };
addé¢æ°ãå¼ã³åºãæã¯ãã³ãã¬ã¼ãå¼æ°ã«å ·ä½çãªãã£ã¹ããããããé¢æ°ã®å¼æ°ã®å2ã¤ã渡ãã¾ããstatic_dispatcherã®æã¯ãã£ã¹ããããããé¢æ°ã®ã·ã°ããã£ã¯å ·ä½çãªåã§ç°ãªã£ã¦ãã¾ããããmapped_typeã¯1éããªã®ã§ãå ¨ã¦ã®ãã£ã¹ãããé¢æ°ãåãã·ã°ããã£ã§ãªããã°ãªãã¾ããã*2ãã£ã¦basic_dispatcherã«æ¸¡ãé¢æ°ãã¤ã³ã¿ã¯ãå¼æ°ãåºåºã¯ã©ã¹ã®åç §ãåãé¢æ°ã§ãªããã°ãªãã¾ãããå ·ä½çãª(åçãª)åã¯ãé¢æ°å é¨ã§é©åã«dynamic_castããããã¨ã§å¾ã¾ãã
basic_dispatcherã使ç¨ããã³ã¼ãã§ãã
struct shape { virtual ~shape() {} }; struct rectangle : shape {}; struct ellipse : shape {}; struct polygon : shape {}; struct round_rectangle : rectangle {}; void is_hit_rectangle_and_rectangle_(shape&, shape&) { std::cout << "rectangle and rectangle" << std::endl; } void is_hit_rectangle_and_ellipse_(shape&, shape&) { std::cout << "rectangle and ellipse" << std::endl; } void is_hit_rectangle_and_polygon_(shape&, shape&) { std::cout << "rectangle and polygon" << std::endl; } void is_hit_rectangle_and_round_rectangle_(shape&, shape&) { std::cout << "rectangle and round_rect" << std::endl; } // ä¸ç¥... void is_hit_round_rectangle_and_rectangle_(shape&, shape&) { std::cout << "round_rect and rectangle" << std::endl; } void is_hit_round_rectangle_and_ellipse_(shape&, shape&) { std::cout << "round_rect and ellipse" << std::endl; } void is_hit_round_rectangle_and_polygon_(shape&, shape&) { std::cout << "round_rect and polygon" << std::endl; } void is_hit_round_rectangle_and_round_rectangle_(shape&, shape&) { std::cout << "round_rect and round_rect" << std::endl; } void basic_dispatch_test(std::vector<shape*>& v) { using dispatcher = basic_dispatcher<shape>; dispatcher disp; disp.add<rectangle, rectangle>(is_hit_rectangle_and_rectangle_); disp.add<rectangle, ellipse>(is_hit_rectangle_and_ellipse_); disp.add<rectangle, polygon>(is_hit_rectangle_and_polygon_); disp.add<rectangle, round_rectangle>(is_hit_rectangle_and_round_rectangle_); disp.add<ellipse, rectangle>(is_hit_ellipse_and_rectangle_); disp.add<ellipse, ellipse>(is_hit_ellipse_and_ellipse_); disp.add<ellipse, polygon>(is_hit_ellipse_and_polygon_); disp.add<ellipse, round_rectangle>(is_hit_ellipse_and_round_rectangle_); disp.add<polygon, rectangle>(is_hit_polygon_and_rectangle_); disp.add<polygon, ellipse>(is_hit_polygon_and_ellipse_); disp.add<polygon, polygon>(is_hit_polygon_and_polygon_); disp.add<polygon, round_rectangle>(is_hit_polygon_and_round_rectangle_); disp.add<round_rectangle, rectangle>(is_hit_round_rectangle_and_rectangle_); disp.add<round_rectangle, ellipse>(is_hit_round_rectangle_and_ellipse_); disp.add<round_rectangle, polygon>(is_hit_round_rectangle_and_polygon_); disp.add<round_rectangle, round_rectangle>(is_hit_round_rectangle_and_round_rectangle_); for (auto& i : v) { for (auto& j : v) { disp.go(*i, *j); } } }
å®è¡çµæ
round_rect and round_rect round_rect and rectangle round_rect and ellipse round_rect and polygon rectangle and round_rect rectangle and rectangle rectangle and ellipse rectangle and polygon ellipse and round_rect ellipse and rectangle ellipse and ellipse ellipse and polygon polygon and round_rect polygon and rectangle polygon and ellipse polygon and polygon ------------------------- ------------------------- ç¶è¡ããã«ã¯ä½ããã¼ãæ¼ãã¦ãã ãã . . .
addé¢æ°ã®å¼ã³åºãéãæããããã¨ã«ãªã£ã¦ãã¾ãããããã¯ã¾ã basic_dispatcherã«å¯¾ç§°æ§ãå®è£
ãã¦ããªãããã§ãå¾ã«æ¹åããã¾ãã
ä»åãã¾ãã¾addé¢æ°ã1ç®æã§å¼ã³åºãã¦ãã¾ãããå®éã«ã¯basic_dispatcher
ãã®æç¹ã§ãstatic_dispatcherã¨æ¯ã¹ã¦åªãã¦ããç¹ã3ã¤ããã¾ãã
- é層ã®ã¯ã©ã¹ãå¢ãã¦ãéã
- é層ã®ã¯ã©ã¹ã«å¯¾ããä¾å度ãä½ã
- static_dispatcherãããã³ã³ãã¤ã«æéãå®è¡æéãçããã³ã¼ããµã¤ãºãå°ãã
ã§ããããã¡ãªãããããããããã¾ãã
- 対称æ§ããªã
- ãã¡ã³ã¯ã¿ã«å¯¾å¿ãã¦ããªã
- é¢æ°ã®å¼æ°ã®åãåºåºã¯ã©ã¹ã«åºå®ããã¦ãã¾ã
ãã¨ããä¸ã¤å¤§ããªåé¡ãããã¾ããbasic_dispatcherã¯ãªã¹ã³ãã®ç½®æååãå®ã£ã¦ãã¾ããã
ä¾ãåºãã¨é常ã®shape&
ãå¼æ°ã«åãé¢æ°ã¯shapeããæ´¾çããã¯ã©ã¹rectangle
åã®ãªãã¸ã§ã¯ããåãåããã¨ãã§ããä»®æ³é¢æ°ããªã¼ãã¼ã©ã¤ãããªãéãshape
ã¨åãæ¯ãèãããã¾ããsttatic_dispatcherã¯ãã®ã¨ããã«æ¯ãèãã¾ããä¾ã(rectangle&, rectangle&)
ãå¼æ°ã«åãé¢æ°ãç»é²ããªãã¦ã(shape&, rectangle&)
ãåãé¢æ°ãããã°ãã¡ãã«ãã£ã¹ããããããå¦çããã¾ãããããbasic_dispatcherã§ã¯å³å¯ã«ç»é²ããæã®ãã¼ã®type_indexåã®ãã¢ã¨ä¸è´ããé¢æ°ããå¼ã³åºãã¦ããã¾ãããAndreiæ°ã¯Modern C++ Designå·çæç¹ã§ããã®æå¹ãªè§£æ±ºæ¹æ³ãè¦ã¤ãã¦ãã¾ãããç¾æç¹ã§ã¯å
¨ã¦ã®æ¹ã®çµã¿åããã注ææ·±ãç»é²ãã¦ãããªããã°ãªãã¾ããã
æå¾ã«ã3ã¤ã®åé¡ã®ãã¡ãã * é¢æ°ã®å¼æ°ã®åãåºåºã¯ã©ã¹ã«åºå®ããã¦ãã¾ããã¨ããåé¡ã解決ãã¦çµããã«ãã¾ããæ®ã2ã¤ã¯ã次åã®å¯¾æ°æéæ¹è¯ç·¨ã§ããããã¨æãã¾ãã
function_dispatcher
ãã©ã³ããªã³é¢æ°
ãããã¨ã¯åç´ã§ããã£ã¹ãããã£ã¼å
é¨ã§å
·ä½çãªåã¸ãã£ã¹ãããå¦çãããã°è¯ãã§ããå®éã®å¦çã®åã«ã¡ãã£ã¨ããå¦çããã¦ã¡ã¤ã³ã®é¢æ°ãå¼ã³åºãé¢æ°ããã©ã³ããªã³é¢æ°ã¾ãã¯ãµã³ã¯ã¨è¨ãããã§ããã¾ãããã³ãã¬ã¼ãã¯éåãã³ãã¬ã¼ãå¼æ°ã¨ãã¦é¢æ°ãã¤ã³ã¿ã渡ããã¨ãã§ãã¾ããbasic_dispatcherãããã¯ã¨ã³ãã¨ãã¦ãé¢æ°ãã¤ã³ã¿ããã£ã¹ãããããfunction_dispatcherãå®ç¾©ãã¦ã¿ã¾ããé¢æ°ãã¤ã³ã¿ã«çµã£ã¦ããã®ã§ãã¡ã³ã¯ã¿ã¯å¯¾è±¡å¤ã§ãããã¡ã³ã¯ã¿ãèæ
®ãããã£ã¹ãããã£ã¼ã¯æ¬¡åããã¾ãã
function_dispatcherã®ã½ã¼ã¹ã³ã¼ãã§ãã
template < class BaseLhs, class BaseRhs = BaseLhs, class Result = void > class function_dispatcher { basic_dispatcher<BaseLhs, BaseRhs, Result> backend_; public: template <class SomeLhs, class SomeRhs, Result (*CallBack)(SomeLhs&, SomeRhs&)> void add() { struct local { static Result trampoline(BaseLhs& lhs, BaseRhs& rhs) { return CallBack(dynamic_cast<SomeLhs&>(lhs), dynamic_cast<SomeRhs&>(rhs)); } }; backend_.add<SomeLhs, SomeRhs>(&local::trampoline); } Result go(BaseLhs& lhs, BaseRhs& rhs) { return backend_.go(lhs, rhs); } };
å
é¨ã«å®è£
ã¨ãã¦basic_dispatcherãæã£ã¦ãã¾ããaddé¢æ°å
ã§ãå¼æ°ãåºåºã¯ã©ã¹ããæ£ããåã¸ãã£ã¹ãããé¢æ°ã¸è»¢éãããã©ã³ããªã³é¢æ°ãå®ç¾©ããã¦ãã¾ããé¢æ°å
ã«staticãªãã¸ã§ã¯ãã¨ãã¦ä½ã£ã¦ãã¾ãã¨ãåä¸ã®ãªãã¸ã§ã¯ãã¨ãªã£ã¦ãã¾ããããaddã®åº¦ã«ç°ãªããã©ã³ããªã³é¢æ°ãä½æãããããããã¼ã«ã«ã¯ã©ã¹ã使ç¨ãã¦ãã¾ããCallBackã®å¼ã³åºãã¯éæ¥åç
§ã®ããã«è¦ãã¾ããããã©ã³ããªã³é¢æ°ã®ã¢ãã¬ã¹ã¯ã³ã³ãã¤ã«æã«è§£æ±ºãããã®ã§ãã³ã³ãã¤ã©ãæé©åãè¡ãè¨å®ã«ãªã£ã¦ããã°æããã¤ã³ã©ã¤ã³å±éããã¾ãã®ã§ããã©ã³ããªã³é¢æ°ã«ãããªã¼ãã¼ãããããã¾ããã
ç¸å¤ããã対称æ§ãæªå¯¾å¿ã®ããã§addé¢æ°ã®éãå¤ãã§ãããç»é²ã»å¼ã³åºãã¯ä»¥ä¸ã®ããã«ãªãã¾ããã
void function_dispatcher_test(std::vector<shape*>& v) { using dispatcher = function_dispatcher<shape>; dispatcher disp; disp.add<rectangle, rectangle, is_hit_rectangle_and_rectangle>(); disp.add<rectangle, ellipse, is_hit_rectangle_and_ellipse>(); disp.add<rectangle, polygon, is_hit_rectangle_and_polygon>(); disp.add<rectangle, round_rectangle, is_hit_rectangle_and_round_rectangle>(); disp.add<ellipse, rectangle, is_hit_ellipse_and_rectangle>(); disp.add<ellipse, ellipse, is_hit_ellipse_and_ellipse>(); disp.add<ellipse, polygon, is_hit_ellipse_and_polygon>(); disp.add<ellipse, round_rectangle, is_hit_ellipse_and_round_rectangle>(); disp.add<polygon, rectangle, is_hit_polygon_and_rectangle>(); disp.add<polygon, ellipse, is_hit_polygon_and_ellipse>(); disp.add<polygon, polygon, is_hit_polygon_and_polygon>(); disp.add<polygon, round_rectangle, is_hit_polygon_and_round_rectangle>(); disp.add<round_rectangle, rectangle, is_hit_round_rectangle_and_rectangle>(); disp.add<round_rectangle, ellipse, is_hit_round_rectangle_and_ellipse>(); disp.add<round_rectangle, polygon, is_hit_round_rectangle_and_polygon>(); disp.add<round_rectangle, round_rectangle, is_hit_round_rectangle_and_round_rectangle>(); for (auto& i : v) { for (auto& j : v) { disp.go(*i, *j); } } } int main() { std::vector<shape*> v = {new round_rectangle(), new rectangle(), new ellipse(), new polygon()}; function_dispatcher_test(v); std::cout << "-------------------------" << std::endl; for (auto& it : v) { delete it; } }
å®è¡çµæ
round_rect and round_rect round_rect and rectangle round_rect and ellipse round_rect and polygon rectangle and round_rect rectangle and rectangle rectangle and ellipse rectangle and polygon ellipse and round_rect ellipse and rectangle ellipse and ellipse ellipse and polygon polygon and round_rect polygon and rectangle polygon and ellipse polygon and polygon ------------------------- ç¶è¡ããã«ã¯ä½ããã¼ãæ¼ãã¦ãã ãã . . .
static_dispatcherã¨åæ§ã«ãå ·ä½çãªåã®ã·ã°ããã£ã®é¢æ°ã使ããããã«ãªãã¾ãããé¢æ°ã®å¼æ°ã§ã¯ãªããéåãã³ãã¬ã¼ãå¼æ°ã¨ãã¦æ¸¡ãã¦ãã¾ãããã¨ã¯basic_dispatcherã¨åãããã«ä½¿ç¨ã§ãã¾ããããã§basic_dispatcherã«æ¸¡ãé¢æ°ã®å¼æ°ã®æ¹ã®åé¡ã解決ãã¾ãããæ®2ã¤ã®åé¡(対称æ§ã¨ããã¡ã³ã¯ã¿ã¸ã®å¯¾å¿)ã¯æ¬¡åããããã¨æãã¾ãã
*1:ã¡ãªã¿ã«std::pair<std::type_index, std::type_index>ã«å¯¾ããstd::hashã®ç¹æ®åãå®ç¾©ããã°ãunordered_mapã§ããã¼ã¨ãã¦ä½¿ç¨ãããã¨ãã§ããO(1)ã®æ¢ç´¢ãå¯è½ã«ãªãã¨æããã¾ãããããæ¸ç±ã§ããã·ã¥ãããã«ã¤ãã¦ã¯è¨åããã¦ãã¾ããã®ã§ãä»åã¯ç¹ã«è§¦ããã«é²ãã¦ããã¾ã
*2:ããã§ããé¢æ°ã®ã·ã°ããã£ã¯ãæ»ãå¤ã®åã¨å¼æ°ã®åã¨å¼æ°ã®æ°ã¨èãã¦ä¸ãã