将函子作为函数指针传递

发布于 2024-08-13 04:13:29 字数 159 浏览 4 评论 0原文

我正在尝试在 C++ 应用程序中使用 C 库,并发现自己处于以下情况(我了解我的 C,但我对 C++ 相当陌生)。在 C 端,我有一个函数集合,它们以函数指针作为参数。在 C++ 方面,我有带有函子的对象,该函子具有与 C 函数所需的函数指针相同的签名。有没有办法使用C++函子作为函数指针传递给C函数?

I'm trying to use a C library in a C++ app and have found my self in the following situation (I know my C, but I'm fairly new to C++). On the C side I have a collection of functions that takes a function pointer as their argument. On the C++ side I have objects with a functor which has the same signature as the function pointer needed by the C function. Is there any way to use the C++ functor as a function pointer to pass to the C function?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

剧终人散尽 2024-08-20 04:13:29

您不能直接将指向 C++ 仿函数对象的指针作为指向 C 代码的函数指针传递
(甚至 C++ 代码)。

此外,为了可移植地将回调传递给 C 代码,至少需要声明它
作为 extern "C" 非成员函数。
至少,因为某些 API 需要特定的函数调用约定,因此
附加声明修饰符。

在许多环境中,C 和 C++ 具有相同的调用约定,仅不同
在名称修改中,因此任何全局函数或静态成员都可以工作。
但您仍然需要将对 operator() 的调用包装在普通函数中。

  • 如果你的函子没有状态(它是一个对象只是为了满足一些正式的
    要求等):

    类 MyFunctor {
      // 无状态
     民众:
      MyFunctor();
      int 运算符()(SomeType ¶m) const;
    }
    

    你可以编写一个普通的 extern "C" 函数来创建仿函数并执行它
    运算符()。

    extern "C" int MyFunctorInC(SomeType *param)
    {
      静态 MyFunctor my_functor;
      返回 my_functor(*param);
    }
    
  • 如果你的函子有状态,例如:

    类 MyFunctor {
      // 这里有一些字段;
     民众:
      MyFunctor(/* 一些设置状态的参数 */);
      int 运算符()(SomeType ¶m) const;
      // + 一些检索结果的方法。
    }
    

    并且 C 回调函数采用某种用户状态参数(通常为 void *):

    void MyAlgorithmInC(SomeType *arr,
                        int (*fun)(SomeType *, void *),
                        无效*用户状态);
    

    您可以编写一个普通的 extern "C" 函数,将其状态参数转换为
    你的函子对象:

    extern "C" int MyFunctorInC(SomeType *param, void *user_state)
    {
      MyFunctor *my_functor = (MyFunctor *)user_state;
      返回 (*my_functor)(*param);
    }
    

    并像这样使用它:

    MyFunctor my_functor(/* 设置参数 */);
    MyAlgorithmInC(input_data, MyFunctorInC, &my_functor);
    
  • 否则这是唯一正常的方法
    (正常情况如“在运行时不生成机器代码”等)
    就是使用一些静态(全局)或线程本地存储来传递函子
    到外部“C”函数。
    这限制了您可以对代码执行的操作,并且很丑陋,但可以工作。

You cannot directly pass a pointer to a C++ functor object as a function pointer to C code
(or even to C++ code).

Additionally, to portably pass a callback to C code it needs to be at least declared
as an extern "C" non-member function.
At least, because some APIs require specific function call conventions and thus
additional declaration modifiers.

In many environments C and C++ have the same calling conventions and differ only
in name mangling, so any global function or static member will work.
But you still need to wrap the call to operator() in a normal function.

  • If your functor has no state (it is an object just to satisfy some formal
    requirements etc):

    class MyFunctor {
      // no state
     public:
      MyFunctor();
      int operator()(SomeType ¶m) const;
    }
    

    you can write a normal extern "C" function which creates the functor and executes its
    operator().

    extern "C" int MyFunctorInC(SomeType *param)
    {
      static MyFunctor my_functor;
      return my_functor(*param);
    }
    
  • If your functor has state, eg:

    class MyFunctor {
      // Some fields here;
     public:
      MyFunctor(/* some parameters to set state */);
      int operator()(SomeType ¶m) const;
      // + some methods to retrieve result.
    }
    

    and the C callback function takes some kind of user state parameter (usually void *):

    void MyAlgorithmInC(SomeType *arr,
                        int (*fun)(SomeType *, void *),
                        void *user_state);
    

    you can write a normal extern "C" function which casts its state parameter to
    your functor object:

    extern "C" int MyFunctorInC(SomeType *param, void *user_state)
    {
      MyFunctor *my_functor = (MyFunctor *)user_state;
      return (*my_functor)(*param);
    }
    

    and use it like this:

    MyFunctor my_functor(/* setup parameters */);
    MyAlgorithmInC(input_data, MyFunctorInC, &my_functor);
    
  • Otherwise the only normal way to do it
    (normal as in "without generating machine code at runtime" etc.)
    is to use some static (global) or thread local storage to pass the functor
    to an extern "C" function.
    This limits what you can do with your code and is ugly but will work.

雨的味道风的声音 2024-08-20 04:13:29

我使用谷歌找到了这个“gem”。显然是可能的,但我肯定不会推荐它。直接链接到示例源代码。

I found this "gem" using google. Apparently possible but I sure wouldn't recommend it. Direct link to example source code.

樱花细雨 2024-08-20 04:13:29

不,当然。 C 函数的签名将参数作为函数。

void f(void (*func)())
{
  func(); // Only void f1(), void F2(), ....
}

所有函子技巧都由模板函数使用:

template<class Func>
void f (Func func)
{
    func(); // Any functor
}

No, of course. The signature of your C function take an argument as function.

void f(void (*func)())
{
  func(); // Only void f1(), void F2(), ....
}

All tricks with functors are used by template functions:

template<class Func>
void f (Func func)
{
    func(); // Any functor
}
天煞孤星 2024-08-20 04:13:29

用 C++ 编写的 C 回调函数必须声明为 extern "C" 函数 - 因此直接使用函子是不可行的。您需要编写某种包装函数来用作该回调,并让该包装函数调用函子。当然,回调协议需要有某种方式将上下文传递给函数,以便它可以到达函子,否则任务会变得非常棘手。大多数回调方案都有一种传递上下文的方法,但我曾经使用过一些没有这种方法的脑残方案。

有关更多详细信息,请参阅此答案(并在注释中查找轶事证据,表明回调必须是 extern "C" 而不仅仅是静态成员函数):

A C callback function written in C++ must be declared as an extern "C" function - so using a functor directly is out. You'll need to write some sort of wrapper function to use as that callback and have that wrapper call the functor. Of course, the callback protocol will need to have some way of passing context to the function so it can get to the functor, or the task becomes quite tricky. Most callback schemes have a way to pass context, but I've worked with some brain-dead ones that don't.

See this answer for some more details (and look in the comments for anecdotal evidence that the callback must be extern "C" and not just a static member function):

拥有 2024-08-20 04:13:29

我认为你不能:函数对象中的operator()实际上是一个成员函数,而C对它们一无所知。

您应该能够使用免费的 C++ 函数或类的静态函数。

I don't think you can: operator() in a function object is really a member function, and C doesn't know anything about those.

What you should be able to use are free C++ functions, or static functions of classes.

黎歌 2024-08-20 04:13:29

GCC 允许您将成员函数指针转换为普通函数指针(普通函数指针调用的函数的第一个参数是 this)。

查看手册中的相应链接

这需要 -Wno-pmf-conversions 标志,以便消除针对绝对非标准功能的相应警告。对于 C 风格库与 C++ 风格编程的接口非常方便。当成员函数指针是常量时,甚至根本不需要生成任何代码:API 无论如何都会使用该参数顺序。

如果您已经有一个函子,以这种方式扁平化函子可能意味着扁平化其operator(),为您提供一个必须使用仿函数类指针本身作为其第一个参数来调用的函数。这不一定有多大帮助,但至少有 C 链接。

但至少当您不使用函子时,这是有帮助的,并且为 中的 std::mem_fn 提供了一个严肃的 C 链接替代。

GCC allows you to convert member function pointers to plain function pointers (the first argument of the function called by the plain function pointer then is this).

Check out the respective link in the manual.

This requires the -Wno-pmf-conversions flag in order to silence the respective warning for the decidedly non-standard feature. Very convenient for interfacing C style libraries with C++ style programming. When the member function pointer is a constant, this does not even need to generate any code at all: the API would use that argument order anyway.

If you already have a functor, flattening the functor in that manner will likely mean flattening its operator(), giving you a function that has to be called with a functor class pointer itself as its first argument. Which does not necessarily help all that much but at least has C linkage.

But at least when you are not going through functors this is helpful and provides a no-nonsense C linkage replacement for std::mem_fn from <functional>.

债姬 2024-08-20 04:13:29

这取决于这是一个静态方法还是实例方法,如果是静态方法,那么您可以将函数作为 className::functionName 传递,如果它是实例方法,则更加复杂,因为您显然需要绑定到某个实例但不能像使用 C# 等中的委托那样执行此操作。

我发现执行此操作的最佳方法是创建一个持有类,该类使用对象的实例以及函数指针进行实​​例化,然后持有类可以直接调用该函数。

It depends if this is a static or instance method, if it is static then you can pass through the function as className::functionName, if it is an instance method it is fair more complicated, because you obviously need to tie to a certain instance but can't do it in the same way as you would with delegates in C# etc.

The best way I've found of doing this is to create a holding class which is instantiated with the instance of the object as well as the function pointer, the holding class can then invoke the function directly.

深白境迁sunset 2024-08-20 04:13:29

我会说不,因为 C++ 仿函数有一个重载的运算符 (),它是一个成员函数,因此需要一个成员函数指针。这是与普通 C 函数指针完全不同的数据类型,因为没有类的实例就无法调用它。您需要将普通函数或静态成员函数传递给 C 库。由于重载的 () 运算符不能是静态的,因此您不能这样做。您需要向 C 库传递一个普通的非成员函数或静态成员函数,然后您可以从中调用 C++ 仿函数。

I would say no, because a C++ functor has an overloaded operator () which is a member function, and would thus require a member function pointer. This is a totally different data type than a normal C function pointer, since it cannot be invoked without an instance of the class. You'd need to pass a normal function or a static member function to the C library. Since an overloaded () operator can't be static, you can't do it. You'd need to pass the C-library a normal, non-member function or static member function, from which you can then invoke the C++ functor.

清醇 2024-08-20 04:13:29

嗯,也许您可​​以编写一个免费的模板函数来包装您的函数对象。如果它们都有相同的签名,那么这应该可行。像这样(未测试):

template<class T>
int function_wrapper(int a, int b) {
    T function_object_instance;

    return funcion_object_instance( a, b );
}

这适用于所有采用两个 int 并返回 int 的函数。

Hm, maybe you could write a free template function that wraps around your function-objects. If they all have the same signature, this should work. Like this (not tested):

template<class T>
int function_wrapper(int a, int b) {
    T function_object_instance;

    return funcion_object_instance( a, b );
}

This would do for all function that take two ints and return an int.

围归者 2024-08-20 04:13:29

许多采用函数指针回调的 C API 都有一个用于用户状态的 void* 参数。如果您拥有其中之一,那么您很幸运 - 您可以使用 exterm C 函数,该函数将用户数据视为某种引用或键来查找函子,然后执行它。

否则,不行。

Many C APIs that take function pointer callbacks have a void* parameter for user state. If you've got one of those, you're in luck - you can use an exterm C function that treats the user data as some sort of reference or key to lookup the functor, then execute it.

Otherwise, no.

瀟灑尐姊 2024-08-20 04:13:29

使用C++11,可以使用std::bind来解决问题

#include <stdio.h>
#include <functional>

class aClass
{
public:
  int i = 5;
  aClass(int i_) : i(i_) {}
  void operator()(int a, int b) {
      i = i + 1;
      printf ("%d + %d = %d  i = %d\n", a, b, a + b + i, i);
  }
};

void test (int a, int b)
{
  printf ("%d - %d = %d\n", a, b, a - b);
}

template <class op>
void function1 (op function)
{
  function (1, 1);
}

int
main (int argc, const char *argv[])
{
  aClass a(1);
  //  function1 (a);  // this is the wrong way of using it

  using namespace std::placeholders;
  std::function<void(int,int)>  callback;
  callback = std::bind(&aClass::operator(), &a, _1, _2);
  
  function1 (callback);
  function1 (callback);

  function1 (test);
  function1 (test);

  return 0;
}

With C++11, you can use std::bind to solve the problem

#include <stdio.h>
#include <functional>

class aClass
{
public:
  int i = 5;
  aClass(int i_) : i(i_) {}
  void operator()(int a, int b) {
      i = i + 1;
      printf ("%d + %d = %d  i = %d\n", a, b, a + b + i, i);
  }
};

void test (int a, int b)
{
  printf ("%d - %d = %d\n", a, b, a - b);
}

template <class op>
void function1 (op function)
{
  function (1, 1);
}

int
main (int argc, const char *argv[])
{
  aClass a(1);
  //  function1 (a);  // this is the wrong way of using it

  using namespace std::placeholders;
  std::function<void(int,int)>  callback;
  callback = std::bind(&aClass::operator(), &a, _1, _2);
  
  function1 (callback);
  function1 (callback);

  function1 (test);
  function1 (test);

  return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文