2017-11-01 17 views
0

현재 구성원 함수 콜백 함수를 라이브러리 portaudio에 정의 된 비 멤버 함수에 전달하는 데 문제가 있습니다.비 멤버 함수 포인터가 필요할 때 멤버 함수 포인터 전달?

이 내 클래스를 정의하는 방법입니다 start_record()

class record { 
public: 
    record(); 
    void start_record(); 
    int recordCallback(const void *inputBuffer, void *outputBuffer, 
         unsigned long framesPerBuffer, 
         const PaStreamCallbackTimeInfo* timeInfo, 
         PaStreamCallbackFlags statusFlags, void *userData); 
private: 
    PaStreamParameters inputParameters, 
         outputParameters; 
    PaStream*   stream; 
    PaError    err = paNoError; 
    paTestData   data; 
    int     totalFrames; 
    int     numSamples; 
    int     numBytes; 
    SAMPLE    max, val; 
    double    average; 
}; 

내가 아닌 멤버 함수에 멤버 함수를 통과 .. 내가 클래스 레코드 (콜백)의 멤버 함수를 통과 의미, 비 멤버 함수 Pa_OpenStream()에 전달합니다.

err = Pa_OpenStream(
      &this->stream, 
      &this->inputParameters, 
      NULL,     /* &outputParameters, */ 
      SAMPLE_RATE, 
      FRAMES_PER_BUFFER, 
      paClipOff,  /* we won't output out of range samples so don't bother clipping them */ 
      this->recordCallback, 
      &data); 
if(err != paNoError) 
{ 
    std::cout << "Something wrong - open_stream check" << std::endl; 
    exit(1); 
} 

portaudio

타입의 함수 포인터를 기대

int (*)(const void*, void*, long unsigned int, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*) 
and not 

하지

int (record::)(const void*, void*, long unsigned int, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*) 

빠른 용액 클래스 범위 외부 함수를 정의하고, 변수를 확인하는 것이다 그것을 사용하고 클래스 전역 내에서 정의하지만, 나는 그것을 피하고 싶습니다. 그럼 어떻게 처리할까요?

+0

이 파라미터 유효하다 * * 통과하지 '파싱'. – EJP

답변

2

previous questionduplicate은 아이디어가 있지만 구체적인 코드가 없으므로 여기에 샘플이 나와 있습니다.

첫째, 정적 콜백 함수에 추가하여 class record을 수정

은 정적 기능이라는 점을 제외하면 Pa_OpenStream에 전달할 수 있도록이는, 기존의 콜백과 동일한 서명을 가지고
static int myCallback(const void *inputBuffer, void outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData); 

주 .

는 멤버 함수 콜백을 호출하는 함수를 정의합니다 : 우리는 우리가 클래스 내에서 개최되는 필요한 모든 사용자 데이터가 있기 때문에 여기에 사용자 데이터 포인터로 nullptr을 전달하는

int record::myCallback(const void *inputBuffer, void outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData) 
{ 
    record *pThis = (record *)userData; 
    return pThis->recordCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags, nullptr); 
} 

. 이 콜백은 내부적으로 만 사용되므로 여기 및 함수에서 마지막 매개 변수를 삭제하면됩니다.

콜백을 등록 할 때 사용자 데이터 매개 변수로 this과 함께 새 콜백을 전달하십시오.

err = Pa_OpenStream(
     &this->stream, 
     &this->inputParameters, 
     NULL,     /* &outputParameters, */ 
     SAMPLE_RATE, 
     FRAMES_PER_BUFFER, 
     paClipOff,  /* we won't output out of range samples so don't bother clipping them */ 
     &this->myCallback, 
     this); 

그런 다음 recordCallback에, 당신은 당신이 보통 때와 같이 클래스의 모든 멤버에 액세스 할 수 있습니다.

+0

아 ... 이제 알 겠어 ... 천재 야! – Lamda

2

일반적으로 이렇게하는 방법은 데이터 컨텍스트에 'this'포인터를 전달하고 나중에 콜백에서 추출하는 것입니다. 콜백을 간단한 개인 정적 스텁으로 선언 할 수 있습니다.

예 :

class record 
{ 
    // ... 

    void start_record(); 
    { 
     err = Pa_OpenStream(
        &this->stream, 
        &this->inputParameters, 
        NULL,     /* &outputParameters, */ 
        SAMPLE_RATE, 
        FRAMES_PER_BUFFER, 
        paClipOff,  /* we won't output out of range samples so don't bother clipping them */ 
        &record::recordCallbackStub, // call back our static stub 
        this); // 'this' is the data 
    } 

private: 
    // our member function called back, can be virtual 
    int recordCallback(
     const void *inputBuffer, void *outputBuffer, 
     unsigned long framesPerBuffer, 
     const PaStreamCallbackTimeInfo* timeInfo, 
     PaStreamCallbackFlags statusFlags) // no 'userData' param, since it's 'this' 
    { 
     // do your thing within the record context 
    } 

    // the stub to keep C happy, can be declared as extern "C" or whatever call 
    // convention is required from the library, WINAPI comes to mind. 
    static int recordCallbackStub(
     const void *inputBuffer, 
     void *outputBuffer, 
     unsigned long framesPerBuffer, 
     const PaStreamCallbackTimeInfo* timeInfo, 
     PaStreamCallbackFlags statusFlags 
     void* userData) 
    { 
     auto pThis = reinterpret_cast<record*>(userData); // get back the this pointer. 
     return pThis->recordCallback(/* all parameters, except userData */); 
    } 
}; 
+0

솔루션을 주셔서 감사합니다. 그 참으로 천재 솔루션! – Lamda

+1

환영합니다 ... 아주 일반적인 패턴입니다. 기억에 남을만한 가치가 있습니다. –