Как передать функцию-член в качестве параметра?(Portaudio) - PullRequest
0 голосов
/ 28 декабря 2018

Я пытаюсь создать несколько потоков в portaudio.Это то, что требуется для открытия потока

PaError Pa_OpenDefaultStream( PaStream** stream,
                              int numInputChannels,
                              int numOutputChannels,
                              PaSampleFormat sampleFormat,
                              double sampleRate,
                              unsigned long framesPerBuffer,
                              PaStreamCallback *streamCallback,
                              void *userData );

, и это функция PaStreamCallback.

typedef int PaStreamCallback(
    const void *input, void *output,
    unsigned long frameCount,
    const PaStreamCallbackTimeInfo* timeInfo,
    PaStreamCallbackFlags statusFlags,
    void *userData );

Компилятор не принимает, когда я пытаюсь передать функцию обратного вызова с помощью этого:

std::bind(&MyStreamClass::OutputRouting, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6)

и вот ошибка, которую я получаю:

error: cannot convert 'std::_Bind_helper<false, int (MyStreamClass::*)(const void*, void*, long unsigned int, const PaStreamCallbackTimeInfo*, long unsigned int, void*), MyStreamClass*, const std::_Placeholder<1>&, const std::_Placeholder<2>&, const std::_Placeholder<3>&, const std::_Placeholder<4>&, const std::_Placeholder<5>&, const std::_Placeholder<6>&>::type' {aka 'std::_Bind<int (MyStreamClass::*(MyStreamClass*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>, std::_Placeholder<4>, std::_Placeholder<5>, std::_Placeholder<6>))(const void*, void*, long unsigned int, const PaStreamCallbackTimeInfo*, long unsigned int, void*)>'} to 'int (*)(const void*, void*, long unsigned int, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*)' {aka 'int (*)(const void*, void*, long unsigned int, const PaStreamCallbackTimeInfo*, long unsigned int, void*)'}
 Pa_OpenDefaultStream(&stream, 0, 0, paFloat32, 0, 0, std::bind(&MyStreamClass::OutputRouting, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6), nullptr);

Итак, есть ли способ передать функцию-член в качестве параметра?

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

Есть несколько способов сделать это.Вы можете использовать параметр void* userData, чтобы указать на ваш класс из функции, не являющейся членом (или статической), и получить доступ к вашему классу из этой функции.Или вы можете использовать эту не-членную (или статическую) функцию для вызова функции-члена вашего объекта:

class MyClass
{
public:

    void register_callback_here()
    {
        Pa_OpenDefaultStream(stream, 2, 2, PaSampleFormat::whatever, 44100,
            1024, &MyClass::pa_callback_mapper, this); // PASS this!!!
    }

private:

    // The actual call back
    int callback(
        const void* input, void* output,
        unsigned long frameCount,
        const PaStreamCallbackTimeInfo* timeInfo,
        PaStreamCallbackFlags statusFlags)
    {
        // actual callback here
        return 0;
    }

    // a pass-through function that reinterprets the userData as the this pointer
    // then cals the member function using this.
    static int pa_callback_mapper(
        const void* input, void* output,
        unsigned long frameCount,
        const PaStreamCallbackTimeInfo* timeInfo,
        PaStreamCallbackFlags statusFlags,
        void* userData)
    {
        if(auto self = reinterpret_cast<MyClass*>(userData))
            return self->callback(input, output, frameCount, timeInfo, statusFlags);
        return 0;
    }
};

Когда вы регистрируете обратный вызов, вы передаете this как userData.Обратный вызов возвращает вам этот указатель в вашей функции обратного вызова.Вы можете привести его обратно к вашему типу класса и либо получить к нему доступ через класс, либо перенаправить вызов функции-члену (как в этом примере).

0 голосов
/ 28 декабря 2018

Ваш обратный вызов должен быть примерно таким:

int MyCallback(
    const void *input, void *output,
    unsigned long frameCount,
    const PaStreamCallbackTimeInfo* timeInfo,
    PaStreamCallbackFlags statusFlags,
    void *userData )
{
    return reinterpret_cast<MyStreamClass*>(userData)->OutputRouting(input, output, frameCount, timeInfo, statusFlags);
}
...