模板魔术用于包装采用void *参数的C回调? [英] template magic for wrapping C callbacks that take void* parameters?

查看:127
本文介绍了模板魔术用于包装采用void *参数的C回调?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说我使用的是一个C API,可让您注册带有 void * 关闭的回调:

Say I'm using a C API that lets you register callbacks that take a void* closure:

void register_callback(void (*func)(void*), void *closure);

在C ++中,拥有比 void * 所以我想创建一个包装器,让我注册强类型的C + +回调代替:

In C++ it's nice to have stronger types than void* so I want to create a wrapper that lets me register strongly-typed C++ callbacks instead:

template <typename T, void F(T*)>
void CallbackWrapper(void *p) {
  return F(static_cast<T*>(p));
}

void MyCallback(int* param) {}

void f(void *closure) {
  register_callback(CallbackWrapper<int, MyCallback>, closure);
}

这个解决方案的一个不错的属性是它可以内联我的回调到包装器,所以这个包装方案有零开销。我认为这是一个要求。

This works alright. One nice property of this solution is that it can inline my callback into the wrapper, so this wrapping scheme has zero overhead. I consider this a requirement.

但是如果我可以让API看起来更像这样会很好:

But it would be nice if I could make the API look more like this:

void f2() {
  RegisterCallback(MyCallback, closure);
}



我希望我可以通过推断模板参数来实现上述目的。但我不能弄清楚如何使它的工作。我到目前为止的尝试是:

I hope I can achieve the above by inferring template parameters. But I can't quite figure out how to make it work. My attempt so far is:

template <typename T>
void RegisterCallback(void (*f)(T*), T* closure) {
  register_callback(CallbackWrapper<T, f>, closure);
}

但这不起作用。任何人都有一个魔术咒语,将使 f2()工作,同时保留零开销性能特性?我想要在C ++ 98中工作。

But this doesn't work. Anyone have a magic incantation that will make f2() work above, while retaining the zero-overhead performance characteristic? I want something that will work in C++98.

推荐答案

我发现这个问题比其他答案更好的答案给我这里! (实际上是Google内部的另一位建议他的工程师)。

I have discovered a better answer to this question than the other answers given to me here! (Actually it was another engineer inside Google who suggested it).

您必须重复函数名称两次,但可以使用宏来解决。

You have to repeat the function name twice, but that can be solved with a macro.

基本模式是:

// Func1, Func2, Func3: Template classes representing a function and its
// signature.
//
// Since the function is a template parameter, calling the function can be
// inlined at compile-time and does not require a function pointer at runtime.
// These functions are not bound to a handler data so have no data or cleanup
// handler.
template <class R, class P1, R F(P1)>
struct Func1 {
  typedef R Return;
  static R Call(P1 p1) { return F(p1); }
};

// ...

// FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function
// *signature*, but without a specific function attached.
//
// These classes contain member functions that can be invoked with a
// specific function to return a Func/BoundFunc class.
template <class R, class P1>
struct FuncSig1 {
  template <R F(P1)>
  Func1<R, P1, F> GetFunc() { return Func1<R, P1, F>(); }
};

// ...

// Overloaded template function that can construct the appropriate FuncSig*
// class given a function pointer by deducing the template parameters.
template <class R, class P1>
inline FuncSig1<R, P1> MatchFunc(R (*f)(P1)) {
  (void)f;  // Only used for template parameter deduction.
  return FuncSig1<R, P1>();
}

// ...

// Function that casts the first parameter to the given type.
template <class R, class P1, R F(P1)>
R CastArgument(void *c) {
  return F(static_cast<P1>(c));
}

template <class F>
struct WrappedFunc;

template <class R, class P1, R F(P1)>
struct WrappedFunc<Func1<R, P1, F> > {
  typedef Func1<R, void*, CastArgument<R, P1, F> > Func;
};

template <class T>
generic_func_t *GetWrappedFuncPtr(T func) {
  typedef typename WrappedFunc<T>::Func Func;
  return Func().Call;
}

// User code:

#include <iostream>

typedef void (generic_func_t)(void*);

void StronglyTypedFunc(int *x) {
  std::cout << "value: " << *x << "\n";
}

int main() {
  generic_func_t *f = GetWrappedFuncPtr(
      MatchFunc(StronglyTypedFunc).GetFunc<StronglyTypedFunc>());
  int x = 5;
  f(&x);
}

这不简单或简单,但它是正确的,

This is not short or simple, but it is correct, principled, and standard-compliant!

它让我想要什么:


  • 写入StronglyTypedFunc()获取指向特定事物的指针。

  • 此函数可以使用void *参数调用。

  • 函数开销或间接。

这篇关于模板魔术用于包装采用void *参数的C回调?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆