C++ 将Gravity(脚本语言)调用转换为本机C函数调用

C++ 将Gravity(脚本语言)调用转换为本机C函数调用,c++,c,calling-convention,scripting-language,gravity-language,C++,C,Calling Convention,Scripting Language,Gravity Language,我目前正在研究实现一种更干净的方法,从脚本语言调用本机C函数 到目前为止,最简单的例子是: int add(int lhs, int rhs) { return lhs + rhs; } static void gravity_wrap_add( gravity_vm* vm, gravity_value_t* args, uint32_t nargs, uint32_t retIndex, void* data ) { int lhs, rhs, rt; // U

我目前正在研究实现一种更干净的方法,从脚本语言调用本机C函数

到目前为止,最简单的例子是:

int add(int lhs, int rhs) {
  return lhs + rhs;
}

static void gravity_wrap_add(
  gravity_vm* vm,
  gravity_value_t* args, uint32_t nargs, 
  uint32_t retIndex, void* data
) {
  int lhs, rhs, rt;

  // Unwrap
  lhs = VALUE_AS_INT(args[1]);
  rhs = VALUE_AS_INT(args[2]);

  // Perform call, capture return
  rt = add(lhs, rhs);

  // Forward the return
  gravity_vm_setslot(vm, VALUE_FROM_INT(rt), retIndex);
}
static void gravity_wrap_add(
  gravity_vm* vm,
  gravity_value_t* args, uint32_t nargs, 
  uint32_t retIndex, void* data
) {
  gravity_vm_setslot(vm, 
   VALUE_FROM_INT(
     add(VALUE_AS_INT(args[1]), VALUE_AS_INT(args[2]))
   ), 
  retIndex);
}

使用C++(98)模板或C预处理器魔术,有没有一种方法生成包装函数?< /P> 上述包装器函数的一个非常非常复杂的例子是:

int add(int lhs, int rhs) {
  return lhs + rhs;
}

static void gravity_wrap_add(
  gravity_vm* vm,
  gravity_value_t* args, uint32_t nargs, 
  uint32_t retIndex, void* data
) {
  int lhs, rhs, rt;

  // Unwrap
  lhs = VALUE_AS_INT(args[1]);
  rhs = VALUE_AS_INT(args[2]);

  // Perform call, capture return
  rt = add(lhs, rhs);

  // Forward the return
  gravity_vm_setslot(vm, VALUE_FROM_INT(rt), retIndex);
}
static void gravity_wrap_add(
  gravity_vm* vm,
  gravity_value_t* args, uint32_t nargs, 
  uint32_t retIndex, void* data
) {
  gravity_vm_setslot(vm, 
   VALUE_FROM_INT(
     add(VALUE_AS_INT(args[1]), VALUE_AS_INT(args[2]))
   ), 
  retIndex);
}

<>这个版本在技术上是我想要达到的,但是通过像预处理器或C++模板这样的方法。出于跨平台兼容性的原因,我希望坚持使用C++98(因为MSVC在现代功能上并不太好)。

没有可变模板的话,这是相当乏味的,但您应该能够执行一些参数:

namespace gravity {
  template<class T> struct value {};
  // for brevity and deduction:
  template<class T> T get(const gravity_value_t &v)
  {return value<T>::get(v);}
  template<class T> gravity_value_t put(const T &t)
  {return value<T>::put(t);}
  template<> struct value<int> {
    int get(const gravity_value_t &v)
    {return VALUE_AS_INT(v);}
    gravity_value_t put(int i)
    {return VALUE_FROM_INT(i);}
  };
  // more specializations…

  template<class R,R f()>
  void wrap(gravity_vm* vm,
            gravity_value_t* args, uint32_t nargs, 
            uint32_t retIndex, void* data) {
    assert(nargs==0);
    gravity_vm_setslot(vm,put(f()),retIndex);
  }
  template<class R,class A,R f(A)>
  void wrap(gravity_vm* vm,
            gravity_value_t* args, uint32_t nargs, 
            uint32_t retIndex, void* data) {
    assert(nargs==1);
    gravity_vm_setslot(vm,put(f(get<A>(args[0]))),retIndex);
  }
  // more overloads with more arguments…

  /*gravity_register*/(wrap<int,int,int,add>);
}
名称空间重力{
模板结构值{};
//为了简洁明了:
模板T获取(常量重力值T&v)
{返回值::get(v);}
模板重力值输入(常数t&t)
{返回值::put(t);}
模板结构值{
int get(恒定重力值t&v)
{返回值_为_INT(v);}
重力值输入(int i)
{返回值_FROM_INT(i);}
};
//更多专业…
模板
无效包裹(重力_vm*vm,
重力值,
uint32_t重新索引,无效*数据){
断言(nargs==0);
重力(vm)(vm,put(f),retIndex);;
}
模板
无效包裹(重力_vm*vm,
重力值,
uint32_t重新索引,无效*数据){
断言(nargs==1);
重力(vm)设定点(vm,put(f(get(args[0])),retIndex ;;
}
//具有更多参数的更多重载…
/*重力寄存器*/(包裹);
}
像往常一样,
void
返回类型将是一种痛苦;必须为
void
R
重复每个参数计数重载


在使用
wrap
时,可以使用演绎法来避免重复签名,但这样可以得到较少的函数和额外的闭包对象来区分它们(您可以通过
data
参数来使用这些对象)。

很难准确地说出您在尝试什么,但如果我理解,您可以包括
limits.h
gravity\u wrap\u add
validate
INT\u MIN