#include <iostream>
#include <sstream>
#include <string>
#include <iterator>
#include <functional>
#include <memory>
#include <vector>
#include <map>
#include <typeinfo>
#include <stdexcept>
using namespace std;

struct Base {
  virtual ~Base() = 0;
  virtual void print_to(std::ostream &) const = 0;
};
inline Base::~Base() {}

template<typename Target>
struct Storage : public Base {
  Target value;
  Storage (Target t) // screw perfect forwarding :D
   : value(std::forward<Target>(t)) {}

  void print_to(std::ostream & stream) const {
    stream << value;
  }
};

struct Any {
  std::shared_ptr<Base const> value;

  template<typename Target>
  Target const & as(void) const {
    return
      dynamic_cast<Storage<Target> const &>(*value).value;
   }
   template<typename T>
   operator T const &(void) const {
     return as<T>();
  }
   friend std::ostream & operator<<(std::ostream& stream, Any const & thing) {
     thing.value->print_to(stream);
     return stream;
   }
};

template<typename Target>
Any make_any(Target && value) {
  return Any{std::make_shared<Storage<typename std::remove_reference<Target>::type> const>(std::forward<Target>(value))};
}

Any parse_literal(std::string const & literal) {
  try {
    std::size_t next;
    auto integer = std::stoi(literal, & next);
    if (next == literal.size()) {
      return make_any (integer);
    }
    auto floating = std::stod(literal, & next);
    if (next == literal. size()) {
      return make_any (floating);
    }
  } catch (std::invalid_argument const &) {}
  // not very sensible, string literals should better be
  // enclosed in some form of quotes, but that's the
  // job of the parser
  return make_any<std:: string> (std::string{literal});
}

std::istream & operator>>(std::istream & stream, Any & thing) {
  std::string raw;
  if (stream >> raw) {
    thing = parse_literal (raw);
  }
  return stream;
}

// Arguments type to the function "interface"
using Arguments = std::vector<Any> const &;
// the interface
using Function = std::function<Any (Arguments)>;

// Base case of packing a function.
// If it's taking a vector and no more
// arguments, then there's nothing left to
// pack.
template<
  std::size_t N,
  typename Fn>
Function pack(Fn && fn) {
 return
  [fn = std::forward<decltype(fn)>(fn)]
  (Arguments arguments)
  {
   if (N != arguments.size()) {
    throw
      std::string{"wrong number of arguments, expected "} +
      std::to_string(N) +
      std::string{" but got "} +
      std::to_string(arguments.size());
   }
   return fn(arguments);
  };
}

// pack a function to a function that takes
// it's arguments from a vector, one argument after
// the other.
template<
  std::size_t N,
  typename Arg,
  typename... Args,
  typename Fn>
Function pack(Fn && fn) {
 return pack<N+1, Args...>(
  [fn = std::forward<decltype(fn)>(fn)]
  (Arguments arguments, Args const &... args)
  {
   try {
    return fn(
      arguments,
      arguments.at(N),
      args...);
   } catch (std:: bad_cast const &) {
    throw std::string{"argument "} + std::to_string (N) +
      std::string{" has wrong type "};
   }
  });
}


// transform a function into one that takes its
// arguments from a vector
template<
  typename... Args,
  typename Fn>
Function pack_function(Fn && fn) {
 return pack<0, Args...>(
  [fn = std::forward<decltype(fn)>(fn)]
  (Arguments arguments, Args const &... args)
  {
   return make_any(fn(args...));
  });
}


Any apply (multimap<string, Function> const & map, string const & name, Arguments arguments) {
 auto range = map.equal_range(name);
 for (auto function = range.first;
      function != range.second;
      ++function) {
  try {
   return (function->second)(arguments);
  } catch (string const &) {}
 }
 throw string {" no such function "};
}


int eg(int a,int b){ return a+b;}
int eg(int a,int b, string c){return a+b+c.length();}
double eh(string a){return a.size()/double(2);}
int main(){
 multimap<string, Function> func_map;
 func_map.insert(make_pair(
   "eg",pack_function<int,int>(
     static_cast<int(*)(int, int)>(&eg))));
 func_map.insert(make_pair(
   "eg",pack_function<int,int,string>(
     static_cast<int (*)(int, int, string)>(&eg))));
 func_map.insert(make_pair(
   "eh",pack_function<string>(eh)));

 // auto p1=make_tuple(1,2);
 // if you want tuples, just write a
 // function to covert them to a vector
 // of Any.
 Arguments p1 =
   {make_any (1), make_any (2)};
 int result1 =
   apply(func_map, "eg", p1).as<int>();

 vector<Any> p2{p1};
 p2.push_back(make_any<string> ("test"));
 int result2 =
   apply(func_map, "eg", p2).as<int>();


 Arguments p3 = {make_any<string>("testagain")};
 double result3 =
   apply(func_map, "eh", p3).as<double>();


 cout << result1 << endl;
 cout << result2 << endl;
 cout << result3 << endl;
 return 0;
}

