Programming

자유 함수가 예상되는 멤버 함수를 어떻게 전달할 수 있습니까?

procodes 2020. 8. 18. 19:19
반응형

자유 함수가 예상되는 멤버 함수를 어떻게 전달할 수 있습니까?


질문은 다음과 같습니다.이 코드를 고려하십시오.

#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;
}

어떻게 사용할 수있는 a'들 aClass::test에 대한 인수로 function1? 나는이 일에 갇혀있다.

클래스 멤버에 액세스하고 싶습니다.


함수 포인터를 사용하는 데 아무런 문제가 없습니다. 그러나 비 정적 멤버 함수에 대한 포인터는 일반 함수 포인터와 다릅니다. 함수에 암시 적 인수로 전달되는 객체에서 멤버 함수를 호출해야합니다. 위의 멤버 함수의 서명은 다음과 같습니다.

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

사용하려는 유형보다는

void (*)(int, int)

한 가지 접근 방식은 멤버 함수를 만드는 것으로 구성 될 수 있습니다. static이 경우 개체를 호출 할 필요가 없으며 유형과 함께 사용할 수 있습니다 void (*)(int, int).

당신이 당신의 클래스의 비 정적 멤버에 액세스해야하는 경우 당신이 함수는 C 인터페이스의 일부이기 때문에, 예를 들어, 함수 포인터, 고수해야 할, 당신의 최선의 선택은 항상를 전달하는 void*함수 포인터와 전화를 복용 함수에 에서 객체를 가져온 void*다음 멤버 함수를 호출 하는 전달 함수를 통해 멤버.

적절한 C ++ 인터페이스에서 함수가 임의의 클래스 유형을 사용하기 위해 함수 객체에 대한 템플릿 인수를 사용하도록하는 것을 원할 수 있습니다. 템플릿 인터페이스를 사용하는 것이 바람직하지 않은 경우 다음과 같은 것을 사용해야합니다 . std::function<void(int, int)>예를 들어를 사용하여 적절하게 호출 가능한 함수 객체를 만들 수 있습니다 std::bind().

클래스 유형 또는 적합한 유형에 대한 템플릿 인수를 사용하는 유형 안전 접근 방식 은 잘못된 유형으로의 캐스트로 인한 오류 가능성을 제거하므로 인터페이스를 std::function<...>사용하는 것보다 바람직 void*합니다.

함수 포인터를 사용하여 멤버 함수를 호출하는 방법을 명확히하기 위해 다음 예제가 있습니다.

// 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);
}

@Pete Becker의 대답은 괜찮지 만 C ++ 11 class의 명시 적 매개 변수로 인스턴스를 전달하지 않고도 수행 할 수 있습니다 function1.

#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;
}

멤버 함수에 대한 포인터는 함수에 대한 포인터와 다릅니다. 포인터를 통해 멤버 함수를 사용하려면 포인터 (분명히)와이를 적용 할 객체가 필요합니다. 해당 버전은 그래서 function1

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

그리고 그것을 부르기 위해 :

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

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);
    });
}

( 라이브 데모 )

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


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:

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

 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


You can stop banging your heads now. Here is the wrapper for the member function to support existing functions taking in plain C functions as arguments. thread_local directive is the key here.

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 existing plain C functions: http://cpp.sh/8exun


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;
}

참고URL : https://stackoverflow.com/questions/12662891/how-can-i-pass-a-member-function-where-a-free-function-is-expected

반응형