代码之家  ›  专栏  ›  技术社区  ›  dagw

将函数作为函数指针传递

  •  38
  • dagw  · 技术社区  · 15 年前

    我试着在C++应用程序中使用C库,在下面的情况中发现了我自己(我知道我的C,但是我对C++是相当新的)。在C端,我有一个函数集合,它以一个函数指针作为参数。在C++方面,我有一个具有函子的对象,它与C函数所需的函数指针具有相同的签名。有没有办法使用C++函子作为函数指针传递给C函数?

    10 回复  |  直到 10 年前
        1
  •  50
  •   Tomek Szpakowicz    10 年前

    不能直接将指针传递给C++函数对象作为C代码的函数指针 (或者甚至到C++代码)。

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

    在许多环境中,C和C++具有相同的调用约定,并且仅不同。 在名称管理中,任何全局函数或静态成员都可以工作。 但你还是需要把电话转到 operator() 在正常功能中。

    • 如果函数没有状态(它只是满足某种形式的 要求等):

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

      您可以编写一个普通的外部“c”函数来创建该函数并执行它的 运算符()。

      extern "C" int MyFunctorInC(SomeType *param)
      {
        static MyFunctor my_functor;
        return my_functor(*param);
      }
      
    • 如果函数具有状态,例如:

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

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

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

      您可以编写一个普通的外部“c”函数,将其状态参数强制转换为 函数对象:

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

      像这样使用:

      MyFunctor my_functor(/* setup parameters */);
      MyAlgorithmInC(input_data, MyFunctorInC, &my_functor);
      
    • 否则这是唯一正常的方法 (正常如“运行时不生成机器代码”等) 是使用一些静态(全局)或线程本地存储来传递函数 到外部“c”函数。 这限制了您可以对代码进行的操作,并且很难看,但会起作用。

        2
  •  7
  •   Andreas Brinck    15 年前

    我发现了这个 gem “使用谷歌。显然可能,但我肯定不会推荐。直接的 link 例如源代码。

        3
  •  5
  •   BenMorel Manish Pradhan    11 年前

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

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

    函数的所有技巧都由 模板 功能:

    template<class Func>
    void f (Func func)
    {
        func(); // Any functor
    }
    
        4
  •  3
  •   Community CDub    8 年前

    用C++编写的C回调函数必须声明为 extern "C" 函数-所以直接使用函数是不可能的。您需要编写某种包装函数来用作回调,并让该包装调用该函数。当然,回调协议需要有某种方式将上下文传递给函数,以便它能够到达函数,或者任务变得相当复杂。大多数回调方案都有一种传递上下文的方法,但我已经处理过一些没有大脑死亡的方案。

    请参阅此答案以了解更多详细信息(并在评论中查找有关回调必须是 外部“C” 而不仅仅是静态成员函数):

        5
  •  2
  •   UncleBens    15 年前

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

    你应该使用的是免费的C++函数,或者类的静态函数。

        6
  •  1
  •   user3996901    10 年前

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

    退房 respective link in the manual .

    这需要 -Wno-pmf-conversions 标记以使非标准功能的相应警告静音。非常方便用C++风格的程序接口连接C风格的库。当成员函数指针是常量时,甚至不需要生成任何代码:无论如何,API都将使用该参数顺序。

    如果已经有了一个函数,那么以这种方式展平该函数可能意味着展平它的 operator() ,为您提供一个函数,该函数必须使用函数类指针本身作为其第一个参数来调用。这不一定对所有这些都有帮助,但至少有C链接。

    但至少当您不使用函数时,这是有帮助的,并为 std::mem_fn <functional> .

        7
  •  0
  •   Tim Ebenezer    15 年前

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

    我找到的最好的方法是创建一个用对象实例和函数指针实例化的保持类,然后保持类可以直接调用函数。

        8
  •  0
  •   Charles Salvia    15 年前

    我会说“否”,因为C++的函子有重载操作符。 () 哪个是 成员函数 ,因此需要成员函数指针。这与普通的C函数指针是完全不同的数据类型,因为没有类的实例就无法调用它。您需要将一个普通函数或静态成员函数传递给C库。因为超载 () 操作员不能是静态的,你不能这样做。您需要通过C库传递一个正常的、非成员函数或静态成员函数,从中可以调用C++函子。

        9
  •  0
  •   Björn Pollex    15 年前

    嗯,也许你可以写一个自由的模板函数,把你的函数对象包装起来。如果他们都有相同的签名,这就可以了。如此(未测试):

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

    这对所有接受两个int并返回一个int的函数都适用。

        10
  •  0
  •   JoeG    15 年前

    许多接受函数指针回调的C API的用户状态都有一个void*参数。如果你有一个这样的函数,你就走运了——你可以使用一个exterm c函数,它把用户数据当作某种引用或键来查找函数,然后执行它。

    否则,没有。