C++ 如何在需要自由函数的地方传递成员函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12662891/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:30:02  来源:igfitidea点击:

How can I pass a member function where a free function is expected?

c++argumentsparameter-passingfunction-pointerspointer-to-member

提问by Jorge Leitao

The question is the following: consider this piece of code:

问题如下:考虑这段代码:

#include <iostream>


class aClass
{
public:
    void aTest(int a, int b)
    {
        printf("%d + %d = %d", a, b, a + b);
    }
};

void function1(void (*function)(int, int))
{
    function(1, 1);
}

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

int main (int argc, const char* argv[])
{
    aClass a();

    function1(&test);
    function1(&aClass::aTest); // <-- How should I point to a's aClass::test function?

    return 0;
}

How can I use the a's aClass::testas an argument to function1? I'm stuck in doing this.

我如何使用a'saClass::test作为参数function1?我坚持这样做。

I would like to access a member of the class.

我想访问班级的成员。

回答by Dietmar Kühl

There isn't anything wrong with using function pointers. However, pointers to non-static member functions are not like normal function pointers: member functions need to be called on an object which is passed as an implicit argument to the function. The signature of your member function above is, thus

使用函数指针没有任何问题。但是,指向非静态成员函数的指针与普通函数指针不同:需要在作为隐式参数传递给函数的对象上调用成员函数。上面的成员函数的签名是,因此

void (aClass::*)(int, int)

rather than the type you try to use

而不是您尝试使用的类型

void (*)(int, int)

One approach could consist in making the member function staticin which case it doesn't require any object to be called on and you can use it with the type void (*)(int, int).

一种方法可能是创建成员函数,static在这种情况下,它不需要调用任何对象,您可以将它与 type 一起使用void (*)(int, int)

If you need to access any non-static member of your class andyou need to stick with function pointers, e.g., because the function is part of a C interface, your best option is to always pass a void*to your function taking function pointers and call your member through a forwarding function which obtains an object from the void*and then calls the member function.

如果您需要访问您的类的任何非静态成员 并且您需要坚持使用函数指针,例如,因为该函数是 C 接口的一部分,您最好的选择是始终将 a 传递void*给您的函数,并使用函数指针并调用您的成员通过转发函数从 中获取对象void*,然后调用成员函数。

In a proper C++ interface you might want to have a look at having your function take templated argument for function objects to use arbitrary class types. If using a templated interface is undesirable you should use something like std::function<void(int, int)>: you can create a suitably callable function object for these, e.g., using std::bind().

在适当的 C++ 接口中,您可能想看看让您的函数为函数对象采用模板化参数以使用任意类类型。如果不希望使用模板化接口,您应该使用类似的东西std::function<void(int, int)>:您可以为这些创建一个合适的可调用函数对象,例如,使用std::bind().

The type-safe approaches using a template argument for the class type or a suitable std::function<...>are preferable than using a void*interface as they remove the potential for errors due to a cast to the wrong type.

使用类类型或合适的模板参数的类型安全方法std::function<...>比使用void*接口更可取,因为它们消除了由于转换为错误类型而导致错误的可能性。

To clarify how to use a function pointer to call a member function, here is an example:

为了阐明如何使用函数指针调用成员函数,这里有一个例子:

// the function using the function pointers:
void somefunction(void (*fptr)(void*, int, int), void* context) {
    fptr(context, 17, 42);
}

void non_member(void*, int i0, int i1) {
    std::cout << "I don't need any context! i0=" << i0 << " i1=" << i1 << "\n";
}

struct foo {
    void member(int i0, int i1) {
        std::cout << "member function: this=" << this << " i0=" << i0 << " i1=" << i1 << "\n";
    }
};

void forwarder(void* context, int i0, int i1) {
    static_cast<foo*>(context)->member(i0, i1);
}

int main() {
    somefunction(&non_member, 0);
    foo object;
    somefunction(&forwarder, &object);
}

回答by Matt Phillips

@Pete Becker's answer is fine but you can also do it without passing the classinstance as an explicit parameter to function1in C++ 11:

@Pete Becker 的回答很好,但您也可以在不将class实例作为显式参数传递给function1C++ 11 的情况下执行此操作:

#include <functional>
using namespace std::placeholders;

void function1(std::function<void(int, int)> fun)
{
    fun(1, 1);
}

int main (int argc, const char * argv[])
{
   ...

   aClass a;
   auto fp = std::bind(&aClass::test, a, _1, _2);
   function1(fp);

   return 0;
}

回答by Pete Becker

A pointer to member function is different from a pointer to function. In order to use a member function through a pointer you need a pointer to it (obviously ) and an object to apply it to. So the appropriate version of function1would be

指向成员函数的指针不同于指向函数的指针。为了通过指针使用成员函数,您需要一个指向它的指针(显然)和一个要应用它的对象。所以合适的版本function1

void function1(void (aClass::*function)(int, int), aClass& a) {
    (a.*function)(1, 1);
}

and to call it:

并称之为:

aClass a; // note: no parentheses; with parentheses it's a function declaration
function1(&aClass::test, a);

回答by Lightness Races in Orbit

Since 2011, if you can change function1, do so, like this:

自 2011 年以来,如果您可以更改function1,请这样做,如下所示:

#include <functional>
#include <cstdio>

using namespace std;

class aClass
{
public:
    void aTest(int a, int b)
    {
        printf("%d + %d = %d", a, b, a + b);
    }
};

template <typename Callable>
void function1(Callable f)
{
    f(1, 1);
}

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

int main()
{
    aClass obj;

    // Free function
    function1(&test);

    // Bound member function
    using namespace std::placeholders;
    function1(std::bind(&aClass::aTest, obj, _1, _2));

    // Lambda
    function1([&](int a, int b) {
        obj.aTest(a, b);
    });
}

(live demo)

现场演示

Notice also that I fixed your broken object definition (aClass a();declares a function).

另请注意,我修复了您损坏的对象定义(aClass a();声明了一个函数)。

回答by Nicola Bertelloni

I asked a similar question (C++ openframeworks passing void from other classes) but the answer I found was clearer so here the explanation for future records:

我问了一个类似的问题(C++ openframeworks 从其他类传递 void)但我找到的答案更清楚,所以这里是对未来记录的解释:

it's easier to use std::function as in:

使用 std::function 更容易,如下所示:

 void draw(int grid, std::function<void()> element)

and then call as:

然后调用为:

 grid.draw(12, std::bind(&BarrettaClass::draw, a, std::placeholders::_1));

or even easier:

甚至更容易:

  grid.draw(12, [&]{a.draw()});

where you create a lambda that calls the object capturing it by reference

在其中创建一个 lambda 来调用通过引用捕获它的对象

回答by mathengineer

I made the member function as static and all works:

我将成员函数设为静态并且一切正常:

#include <iostream>

class aClass
{
public:
    static void aTest(int a, int b)
    {
        printf("%d + %d = %d\n", a, b, a + b);
    }
};

void function1(int a,int b,void function(int, int))
{
    function(a, b);
}

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

int main (int argc, const char* argv[])
{
    aClass a;

    function1(10,12,test);
    function1(10,12,a.aTest); // <-- How should I point to a's aClass::test function?

    getchar();return 0;
}

回答by hLk

Not sure why this incredibly simple solution has been passed up:

不知道为什么这个非常简单的解决方案被忽略了:

#include <stdio.h>

class aClass
{
public:
    void aTest(int a, int b)
    {
        printf("%d + %d = %d\n", a, b, a + b);
    }
};

template<class C>
void function1(void (C::*function)(int, int), C& c)
{
    (c.*function)(1, 1);
}
void function1(void (*function)(int, int)) {
  function(1, 1);
}

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

int main (int argc, const char* argv[])
{
    aClass a;

    function1(&test);
    function1<aClass>(&aClass::aTest, a);
    return 0;
}

Output:

输出:

1 - 1 = 0
1 + 1 = 2

回答by Necktwi

You can stop banging your heads now. Here is the wrapper for the member function to support existingfunctions taking in plain Cfunctions as arguments. thread_localdirective is the key here.

你现在可以停止敲你的头了。这是成员函数的包装器,以支持将普通C函数作为参数的现有函数。指令是这里的关键。thread_local

http://cpp.sh/9jhk3

http://cpp.sh/9jhk3

// Example program
#include <iostream>
#include <string>

using namespace std;

typedef int FooCooker_ (int);

// Existing function
extern "C" void cook_10_foo (FooCooker_ FooCooker) {
    cout << "Cooking 10 Foo ..." << endl;
    cout << "FooCooker:" << endl;
    FooCooker (10);
}

struct Bar_ {
    Bar_ (int Foo = 0) : Foo (Foo) {};
    int cook (int Foo) {
        cout << "This Bar got " << this->Foo << endl;
        if (this->Foo >= Foo) {
            this->Foo -= Foo;
            cout << Foo << " cooked" << endl;
            return Foo;
        } else {
            cout << "Can't cook " <<  Foo << endl;
            return 0;
        }
    }
    int Foo = 0;
};

// Each Bar_ object and a member function need to define
// their own wrapper with a global thread_local object ptr
// to be called as a plain C function.
thread_local static Bar_* BarPtr = NULL;
static int cook_in_Bar (int Foo) {
    return BarPtr->cook (Foo);
}

thread_local static Bar_* Bar2Ptr = NULL;
static int cook_in_Bar2 (int Foo) {
    return Bar2Ptr->cook (Foo);
}

int main () {
  BarPtr = new Bar_ (20);
  cook_10_foo (cook_in_Bar);

  Bar2Ptr = new Bar_ (40);
  cook_10_foo (cook_in_Bar2);

  delete BarPtr;
  delete Bar2Ptr;
  return 0;
}

Please comment on any issues with this approach.

请对此方法的任何问题发表评论。

Other answers fail to call existingplain Cfunctions: http://cpp.sh/8exun

其他答案无法调用现有的普通C函数:http: //cpp.sh/8exun