0

I have a function that I want to be able to runtime check the argument types of as I'm casting a void pointer back to a function. Curious as to how I turn the list of arguments into into a hash using the TypeToEnum template that is constructed like

    #define DEFINE_TYPE(x)\
    template<>\
    struct TypeToEnum<x>\
    {\
      public:\
      static const unsigned int value = HashString(#x);\
    };\

That way I can determine the function signature using templates. I just have no idea how to convert that into a static const array in the invoke method.

    class FunctionDescription
    {
    private:
      int return_type;
      std::vector<int> argument_types;
      std::string m_name;
      void* function;
    public:
const std::string& name() const{ return m_name; }

int ReturnType() const { return return_type; }

const std::vector<int>& arguments() const { return argument_types; }

template<typename Return,typename... Args>
FunctionDescription(const std::string& _name, Return(*func)(Args...)) 
    : m_name(_name), return_type(TypeToEnum<Return>::value)
{
    argument_types = { TypeToEnum<Args>::value... };
    function = func;
}

template<typename Return,typename... Args>
Return invoke(Args... args)
{
    static const int type_check[] = {TypeToEnum<Return>::value,TypeToEnum<std::forward<Args>>::value};

    if (type_check[0] != return_type)
        throw std::exception("Invalid return type for given call");

    for (int i = 1; i < sizeof...(Args) + 1; i++)
    {
        if (type_check[i] != argument_types[i])
            throw std::exception("Invalid argument type for the given call");
    }

    return Return(*func)(Args...)(args...);
}
};
Constructor
  • 7,273
  • 2
  • 24
  • 66
Chase R Lewis
  • 2,119
  • 1
  • 22
  • 47
  • What is DataType? Is there a reason you can't just use `std::function`? – Useless May 15 '14 at 17:59
  • I was originally going to do it without the hash method, but after some messing around got a hash type method to work in visual studio without constexpr. Just hadn't updated my code. Corrected that. I want to have a list of functions of different call signatures. I plan on adding a method eventually that will take a serialized data stream and use the runtime information to call the function (probably have to do some assembly and won't be portable), but I also want this invoke style method to work also. Have no idea how to do either, but want to figure this one out first. – Chase R Lewis May 15 '14 at 18:05

1 Answers1

1

TypeToEnum<std::forward<Args>>::value to TypeToEnum<Args>::value..., but I'd instead do

template<typename Return,typename... Args>
Return invoke(Args...&& args){
  static const int type_check[] = {
    TypeToEnum<Return>::value,TypeToEnum<typename std::decay<Args>::type>::value...
  };

  if (type_check[0] != return_type)
    throw std::exception("Invalid return type for given call");

  for (int i = 1; i <= sizeof...(Args); i++)
  {
    if (type_check[i] != argument_types[i])
      throw std::exception("Invalid argument type for the given call");
  }

  typedef Return(*func_t)(typename std::decay<Args>::type...);
  return static_cast<func_t>(function)( std::forward<Args>(args) );
}

as a first pass. I would then replace decay with a custom type mapping that handles std::reference_wrapper properly, so callers can say "I expect this argument to be a ref" by saying invoke( std::ref(x) ).

Next, I would consider using the typeid instead of all of your machinery. Your hash isn't perfectly reliable, among other problems.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Thanks. std::decay I wasn't aware of. It helps a lot. My one thing about typeid is I want my hash code to be constant across compilers. So hash_code of "int" is the same no matter what. Looking around I don't see a specification that guarantees that. – Chase R Lewis May 16 '14 at 00:40