fork download
  1. #include <unordered_map>
  2. #include <typeinfo>
  3. #include <typeindex>
  4. #include <string>
  5. #include <type_traits>
  6. #include <iostream>
  7. #include <assert.h>
  8. #include <cxxabi.h>
  9. #include <sstream>
  10.  
  11. #include <stdexcept>
  12.  
  13. template <typename Func, Func f>
  14. struct store_func_helper;
  15.  
  16.  
  17. std::string demangle(const std::string& val) {
  18. int status;
  19. char *realname;
  20.  
  21. std::string strname = realname = abi::__cxa_demangle(val.c_str(), 0, 0, &status);
  22. free(realname);
  23. return strname;
  24. }
  25.  
  26. // args will be implicitly converted to arg<T>::type before calling function
  27. // default: convert to const Arg
  28. template <typename Arg, typename snifae=void>
  29. struct arg {
  30. using type = const Arg&;
  31. };
  32.  
  33. // numeric types: convert to double.
  34. template <typename Arg>
  35. struct arg <Arg, typename std::enable_if<std::is_arithmetic<Arg>::value, void>::type> {
  36. using type = double;
  37. };
  38.  
  39. // set more special arg types here.
  40.  
  41.  
  42. // Functions stored in the map are first wrapped in a lambda with this signature.
  43. template <typename Ret, typename... Arg>
  44. using func_type = Ret(*)(typename arg<Arg>::type...);
  45.  
  46. class func_map {
  47. template <typename Func, Func f>
  48. friend class store_func_helper;
  49.  
  50. public:
  51. template <typename Func, Func f>
  52. void store(const std::string& name){
  53. store_func_helper<Func, f>::call(this, name );
  54. }
  55.  
  56. template<typename Ret, typename... Args>
  57. Ret call(std::string func, Args... args){
  58. using new_func_type = func_type<Ret, Args...>;
  59. auto& mapVal = m_func_map.at(func);
  60.  
  61. if (mapVal.second != std::type_index(typeid(new_func_type))){
  62. std::ostringstream ss;
  63. ss << "Error calling function " << func << ", function type: "
  64. << demangle(mapVal.second.name())
  65. << ", attempted to call with " << demangle(typeid(new_func_type).name());
  66. throw std::runtime_error(ss.str());
  67. }
  68. auto typeCastedFun = (new_func_type)(mapVal.first);
  69.  
  70. //args will be implicitly converted to match standardized args
  71. return typeCastedFun(std::forward<Args>(args)...);
  72. };
  73.  
  74.  
  75.  
  76. private:
  77. std::unordered_map<std::string, std::pair<void(*)(),std::type_index> > m_func_map;
  78. };
  79.  
  80. #define FUNC_MAP_STORE(map, func) (map).store<decltype(&func),&func>(#func);
  81.  
  82. template <typename Ret, typename... Args, Ret(*f)(Args...)>
  83. struct store_func_helper<Ret(*)(Args...), f> {
  84. static void call (func_map* map, const std::string& name) {
  85. using new_func_type = func_type<Ret, Args...>;
  86.  
  87. // add a wrapper function, which takes standardized args.
  88. new_func_type lambda = [](typename arg<Args>::type... args) -> Ret {
  89. return (*f)(args...);
  90. };
  91. map->m_func_map.insert(std::make_pair(
  92. name,
  93. std::make_pair((void(*)()) lambda, std::type_index(typeid(lambda)))
  94. ));
  95. }
  96. };
  97.  
  98. //examples
  99.  
  100. long add (int i, long j){
  101. return i + j;
  102. }
  103.  
  104. int total_size(std::string arg1, const std::string& arg2) {
  105. return arg1.size() + arg2.size();
  106. }
  107.  
  108. int main() {
  109. func_map map;
  110. FUNC_MAP_STORE(map, total_size);
  111. FUNC_MAP_STORE(map, add);
  112.  
  113. std::string arg1="hello", arg2="world";
  114. std::cout << "total_size: " << map.call<int>("total_size", arg1, arg2) << std::endl;
  115. std::cout << "add: " << map.call<long>("add", 3, 4) << std::endl;
  116. }
  117.  
  118.  
  119.  
Success #stdin #stdout 0s 15248KB
stdin
Standard input is empty
stdout
total_size: 10
add: 7