code_junkie

What is the simplest way to create and call dynamically a class method in C++?

Nov 13th, 2011
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.14 KB | None | 0 0
  1. typedef std::map<std::string, std::string, std::string, int> actions_type;
  2. typedef actions_type::iterator actions_iterator;
  3.  
  4. actions_type actions;
  5. actions.insert(make_pair(class_name, attribute_name, identifier, method_pointer));
  6.  
  7. //after which I want call the appropriate method in the loop
  8.  
  9. while (the_app_is_running)
  10. {
  11. std::string requested_class = get_requested_class();
  12. std::string requested_method = get_requested_method();
  13.  
  14. //determine class
  15. for(actions_iterator ita = actions.begin(); ita != actions.end(); ++ita)
  16. {
  17. if (ita->first == requested_class && ita->second == requested_method)
  18. {
  19. //class and method match
  20. //create a new class instance
  21. //call method
  22. }
  23. }
  24. }
  25.  
  26. $actions = array
  27. (
  28. "first_identifier" => array("Class1","method1"),
  29. "second_identifier" => array("Class2","method2"),
  30. "third_identifier" => array("Class3","method3")
  31. );
  32.  
  33. while ($the_app_is_running)
  34. {
  35. $id = get_identifier();
  36.  
  37. foreach($actions as $identifier => $action)
  38. {
  39. if ($id == $identifier)
  40. {
  41. $className = $action[0];
  42. $methodName = $action[1];
  43.  
  44. $object = new $className() ;
  45.  
  46. $method = new ReflectionMethod($className , $methodName);
  47. $method -> invoke($object);
  48. }
  49. }
  50. }
  51.  
  52. return_type operator()(variant<possible types...>)
  53.  
  54. #include <boost/variant.hpp>
  55. #include <boost/function.hpp>
  56. #include <boost/bind.hpp>
  57. #include <boost/tuple/tuple.hpp>
  58. #include <boost/mpl/identity.hpp>
  59. #include <boost/function_types/parameter_types.hpp>
  60. #include <boost/function_types/result_type.hpp>
  61. #include <boost/function_types/function_arity.hpp>
  62. #include <boost/preprocessor/repetition.hpp>
  63. #include <map>
  64. #include <string>
  65. #include <iostream>
  66.  
  67. // three totally unrelated classes
  68. //
  69. struct foo {
  70. std::string one() {
  71. return "I ";
  72. }
  73. };
  74.  
  75. struct bar {
  76. std::string two() {
  77. return "am ";
  78. }
  79. };
  80.  
  81. struct baz {
  82. std::string three() const {
  83. return "happy!";
  84. }
  85. };
  86.  
  87. // The following are the parameters you have to set
  88. //
  89.  
  90. // return type
  91. typedef std::string return_type;
  92. // variant storing an object. It contains the list of possible types you
  93. // can store.
  94. typedef boost::variant< foo, bar, baz > variant_type;
  95. // type used to call a function on the object currently active in
  96. // the given variant
  97. typedef boost::function<return_type (variant_type&)> variant_call_type;
  98.  
  99. // returned variant will know what type is stored. C++ got no reflection,
  100. // so we have to have a function that returns the correct type based on
  101. // compile time knowledge (here it's the template parameter)
  102. template<typename Class>
  103. variant_type factory() {
  104. return Class();
  105. }
  106.  
  107. namespace detail {
  108. namespace fn = boost::function_types;
  109. namespace mpl = boost::mpl;
  110.  
  111. // transforms T to a boost::bind
  112. template<typename T>
  113. struct build_caller {
  114. // type of this pointer, pointer removed, possibly cv qualified.
  115. typedef typename mpl::at_c<
  116. fn::parameter_types< T, mpl::identity<mpl::_> >,
  117. 0>::type actual_type;
  118.  
  119. // type of boost::get we use
  120. typedef actual_type& (*get_type)(variant_type&);
  121.  
  122. // prints _2 if n is 0
  123. #define PLACEHOLDER_print(z, n, unused) BOOST_PP_CAT(_, BOOST_PP_ADD(n, 2))
  124. #define GET_print(z, n, unused)
  125. template<typename U>
  126. static variant_call_type get(
  127. typename boost::enable_if_c<fn::function_arity<U>::value ==
  128. BOOST_PP_INC(n), U>::type t
  129. ) {
  130. /* (boost::get<actual_type>(some_variant).*t)(n1,...,nN) */
  131. return boost::bind(
  132. t, boost::bind(
  133. (get_type)&boost::get<actual_type>,
  134. _1) BOOST_PP_ENUM_TRAILING(n, PLACEHOLDER_print, ~)
  135. );
  136. }
  137.  
  138. // generate functions for up to 8 parameters
  139. BOOST_PP_REPEAT(9, GET_print, ~)
  140.  
  141. #undef GET_print
  142. #undef PLACEHOLDER_print
  143.  
  144. };
  145.  
  146. }
  147.  
  148. // incoming type T is a member function type. we return a boost::bind object that
  149. // will call boost::get on the variant passed and calls the member function
  150. template<typename T>
  151. variant_call_type make_caller(T t) {
  152. return detail::build_caller<T>::template get<T>(t);
  153. }
  154.  
  155. // actions stuff. maps an id to a class and method.
  156. typedef std::map<std::string,
  157. std::pair< std::string, std::string >
  158. > actions_type;
  159.  
  160. // this map maps (class, method) => (factory, function pointer)
  161. typedef variant_type (*factory_function)();
  162. typedef std::map< std::pair<std::string, std::string>,
  163. std::pair<factory_function, variant_call_type>
  164. > class_method_map_type;
  165.  
  166. // this will be our test function. it's supplied with the actions map,
  167. // and the factory map
  168. std::string test(std::string const& id,
  169. actions_type& actions, class_method_map_type& factory) {
  170. // pair containing the class and method name to call
  171. std::pair<std::string, std::string> const& class_method =
  172. actions[id];
  173.  
  174. // real code should take the maps by const parameter and use
  175. // the find function of std::map to lookup the values, and store
  176. // results of factory lookups. we try to be as short as possible.
  177. variant_type v(factory[class_method].first());
  178.  
  179. // execute the function associated, giving it the object created
  180. return factory[class_method].second(v);
  181. }
  182.  
  183. int main() {
  184. // possible actions
  185. actions_type actions;
  186. actions["first"] = std::make_pair("foo", "one");
  187. actions["second"] = std::make_pair("bar", "two");
  188. actions["third"] = std::make_pair("baz", "three");
  189.  
  190. // connect the strings to the actual entities. This is the actual
  191. // heart of everything.
  192. class_method_map_type factory_map;
  193. factory_map[actions["first"]] =
  194. std::make_pair(&factory<foo>, make_caller(&foo::one));
  195. factory_map[actions["second"]] =
  196. std::make_pair(&factory<bar>, make_caller(&bar::two));
  197. factory_map[actions["third"]] =
  198. std::make_pair(&factory<baz>, make_caller(&baz::three));
  199.  
  200. // outputs "I am happy!"
  201. std::cout << test("first", actions, factory_map)
  202. << test("second", actions, factory_map)
  203. << test("third", actions, factory_map) << std::endl;
  204. }
  205.  
  206. typedef boost::function<return_type (variant_type&, int)> variant_call_type;
  207.  
  208. return factory[class_method].second(v, 42);
  209.  
  210. struct my_object {
  211. typedef std::string return_type;
  212.  
  213. virtual ~my_object() { }
  214. virtual std::string one() { not_implemented(); }
  215. virtual std::string two() { not_implemented(); }
  216. private:
  217. void not_implemented() { throw std::runtime_error("not implemented"); }
  218. };
  219.  
  220. struct object_factory {
  221. boost::shared_ptr<my_object> create_instance(std::string const& name) {
  222. // ...
  223. }
  224. };
  225.  
  226. typedef boost::function<my_object::return_type(my_object&)> function_type;
  227. typedef std::map< std::pair<std::string, std::string>, function_type>
  228. class_method_map_type;
  229. class_method_map[actions["first"]] = &my_object::one;
  230. class_method_map[actions["second"]] = &my_object::two;
  231.  
  232. boost::shared_ptr<my_object> p(get_factory().
  233. create_instance(actions["first"].first));
  234. std::cout << class_method_map[actions["first"]](*p);
  235.  
  236. class MyClass
  237. {
  238. public:
  239. void function();
  240. };
  241.  
  242. void (MyClass:*function_ptr)() = MyClass::function;
  243.  
  244. MyClass instance;
  245.  
  246. instance.*function_ptr;
  247.  
  248. class MyClass
  249. {
  250. public:
  251. void function();
  252.  
  253. static void call_function(MyClass *instance); // Or you can use a reference here.
  254. };
  255.  
  256. MyClass instance;
  257. MyClass::call_function(&instance);
  258.  
  259. class MyClass
  260. {
  261. public:
  262. enum Method
  263. {
  264. fp_function,
  265. };
  266.  
  267. void function();
  268.  
  269. static void invoke_method(MyClass *instance, Method method); // Or you can use a reference here.
  270. };
  271.  
  272. void MyClass::invoke_method(MyClass *instance, Method method)
  273. {
  274. switch(method)
  275. {
  276. default:
  277. // Error or something here.
  278. return;
  279.  
  280. case fp_function:
  281. instance->function();
  282. break;
  283.  
  284. // Or, if you have a lot of methods:
  285.  
  286. #define METHOD_CASE(x) case fp_##x: instance->x(); break;
  287.  
  288. METHOD_CASE(function);
  289.  
  290. #undef METHOD_CASE
  291. }
  292.  
  293. // Free logging! =D
  294. }
  295.  
  296. MyClass instance;
  297. MyClass::invoke_method(instance, MyClass::fp_function);
  298.  
  299. #include<iostream>
  300. #include<map>
  301. #include<string>
  302.  
  303. using std::map;
  304. using std::string;
  305. using std::cout;
  306. using std::pair;
  307.  
  308. class MVCHandler
  309. {
  310. public:
  311. virtual void operator()(const string& somekindofrequestinfo) = 0;
  312. };
  313.  
  314. class MyMVCHandler : public MVCHandler
  315. {
  316. public:
  317. virtual void operator()(const string& somekindofrequestinfo)
  318. {
  319. cout<<somekindofrequestinfo;
  320. }
  321. };
  322.  
  323. void main()
  324. {
  325. MyMVCHandler myhandler;
  326. map<string, MVCHandler*> handlerMap;
  327. handlerMap.insert(pair<string, MVCHandler*>("mysuperhandler", &myhandler));
  328. (*handlerMap["mysuperhandler"])("somekindofrequestdata");
  329. }
Add Comment
Please, Sign In to add comment