fork(2) download
  1. #include <iostream>
  2. #include <sstream>
  3. #include <string>
  4. #include <iterator>
  5. #include <functional>
  6. #include <memory>
  7. #include <vector>
  8. #include <map>
  9. #include <typeinfo>
  10. #include <stdexcept>
  11. using namespace std;
  12.  
  13. struct Base {
  14. virtual ~Base() = 0;
  15. virtual void print_to(std::ostream &) const = 0;
  16. };
  17. inline Base::~Base() {}
  18.  
  19. template<typename Target>
  20. struct Storage : public Base {
  21. Target value;
  22. Storage (Target t) // screw perfect forwarding :D
  23. : value(std::forward<Target>(t)) {}
  24.  
  25. void print_to(std::ostream & stream) const {
  26. stream << value;
  27. }
  28. };
  29.  
  30. struct Any {
  31. std::shared_ptr<Base const> value;
  32.  
  33. template<typename Target>
  34. Target const & as(void) const {
  35. return
  36. dynamic_cast<Storage<Target> const &>(*value).value;
  37. }
  38. template<typename T>
  39. operator T const &(void) const {
  40. return as<T>();
  41. }
  42. friend std::ostream & operator<<(std::ostream& stream, Any const & thing) {
  43. thing.value->print_to(stream);
  44. return stream;
  45. }
  46. };
  47.  
  48. template<typename Target>
  49. Any make_any(Target && value) {
  50. return Any{std::make_shared<Storage<typename std::remove_reference<Target>::type> const>(std::forward<Target>(value))};
  51. }
  52.  
  53. Any parse_literal(std::string const & literal) {
  54. try {
  55. std::size_t next;
  56. auto integer = std::stoi(literal, & next);
  57. if (next == literal.size()) {
  58. return make_any (integer);
  59. }
  60. auto floating = std::stod(literal, & next);
  61. if (next == literal. size()) {
  62. return make_any (floating);
  63. }
  64. } catch (std::invalid_argument const &) {}
  65. // not very sensible, string literals should better be
  66. // enclosed in some form of quotes, but that's the
  67. // job of the parser
  68. return make_any<std:: string> (std::string{literal});
  69. }
  70.  
  71. std::istream & operator>>(std::istream & stream, Any & thing) {
  72. std::string raw;
  73. if (stream >> raw) {
  74. thing = parse_literal (raw);
  75. }
  76. return stream;
  77. }
  78.  
  79. // Arguments type to the function "interface"
  80. using Arguments = std::vector<Any> const &;
  81. // the interface
  82. using Function = std::function<Any (Arguments)>;
  83.  
  84. // Base case of packing a function.
  85. // If it's taking a vector and no more
  86. // arguments, then there's nothing left to
  87. // pack.
  88. template<
  89. std::size_t N,
  90. typename Fn>
  91. Function pack(Fn && fn) {
  92. return
  93. [fn = std::forward<decltype(fn)>(fn)]
  94. (Arguments arguments)
  95. {
  96. if (N != arguments.size()) {
  97. throw
  98. std::string{"wrong number of arguments, expected "} +
  99. std::to_string(N) +
  100. std::string{" but got "} +
  101. std::to_string(arguments.size());
  102. }
  103. return fn(arguments);
  104. };
  105. }
  106.  
  107. // pack a function to a function that takes
  108. // it's arguments from a vector, one argument after
  109. // the other.
  110. template<
  111. std::size_t N,
  112. typename Arg,
  113. typename... Args,
  114. typename Fn>
  115. Function pack(Fn && fn) {
  116. return pack<N+1, Args...>(
  117. [fn = std::forward<decltype(fn)>(fn)]
  118. (Arguments arguments, Args const &... args)
  119. {
  120. try {
  121. return fn(
  122. arguments,
  123. arguments.at(N),
  124. args...);
  125. } catch (std:: bad_cast const &) {
  126. throw std::string{"argument "} + std::to_string (N) +
  127. std::string{" has wrong type "};
  128. }
  129. });
  130. }
  131.  
  132.  
  133. // transform a function into one that takes its
  134. // arguments from a vector
  135. template<
  136. typename... Args,
  137. typename Fn>
  138. Function pack_function(Fn && fn) {
  139. return pack<0, Args...>(
  140. [fn = std::forward<decltype(fn)>(fn)]
  141. (Arguments arguments, Args const &... args)
  142. {
  143. return make_any(fn(args...));
  144. });
  145. }
  146.  
  147.  
  148. int add (int lhs, int rhs) {
  149. return lhs + rhs;
  150. }
  151.  
  152. double add_floating (double lhs, double rhs) {
  153. return lhs + rhs;
  154. }
  155.  
  156.  
  157. int main(int, char**) {
  158. std::map<std::string, Function> operations;
  159. operations ["add"] = pack_function<int, int>(add);
  160. operations ["addf"] = pack_function<double, double>(add_floating);
  161. operations ["sub"] = pack_function<int, int>(
  162. [](auto lhs, auto rhs) { return lhs - rhs;});
  163. operations ["sum"] = [] (auto summands) {
  164. int result = 0;
  165. for (Any const & e : summands) {
  166. result += e.as<int>();
  167. }
  168. return make_any(result);
  169. };
  170. operations ["hi"] = pack_function<std::string>(
  171. [] (auto name) { return "Hello " + name + ", how are you?";});
  172. std::string line;
  173. while (std::getline(std::cin, line)) {
  174. std::istringstream command{line};
  175. std::string operation;
  176. command >> operation;
  177. std::vector<Any> arguments {
  178. std::istream_iterator<Any>{command},
  179. std::istream_iterator<Any>{} };
  180. auto function = operations.find(operation);
  181. if (function != operations.end ()) {
  182. std::cout << line << " = ";
  183. try {
  184. std::cout << function->second(arguments);
  185. } catch (std::string const & error) {
  186. std::cout << error;
  187. } catch (std::out_of_range const & error) {
  188. std::cout << error. what ();
  189. }
  190. std::cout << std::endl;
  191. }
  192. }
  193. return 0;
  194. }
Success #stdin #stdout 0s 3484KB
stdin
add 5 4
sub 3 2
add 1 2 3
add 4
sum 1 2 3 4
sum
sub 3 1.5
addf 3 3.4
addf 3.0 3.4
hi Pete
stdout
add 5 4 = 9
sub 3 2 = 1
add 1 2 3 = wrong number of arguments, expected 2 but got 3
add 4 = wrong number of arguments, expected 2 but got 1
sum 1 2 3 4 = 10
sum = 0
sub 3 1.5 = argument 1 has wrong type 
addf 3 3.4 = argument 0 has wrong type 
addf 3.0 3.4 = 6.4
hi Pete = Hello Pete, how are you?