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...);
}
};
2
  • What is DataType? Is there a reason you can't just use std::function? Commented May 15, 2014 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. Commented May 15, 2014 at 18:05

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.