How to pass a member function as a parameter? (Por

2019-08-09 16:03发布

问题:

I am trying to create multiple streams in portaudio. This is what it requires for opening a stream

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

and this is the PaStreamCallback function.

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

The compiler doesn't accept when I try to pass my callback function using this:

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

and this is the error I get:

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

So, is there a way I can pass my member-function as a paramter?

回答1:

There are a couple of ways you can do this. You can use the void* userData parameter to point to your class from a non member (or static) function and access your class from that function. Or you can use that non member (or static) function to call a member function on your object:

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

When you register the call back you pass this as the userData. The callback gives that pointer back to you in your callback function. You can cast it back to your class type and either access your class through it or forward the call to a member function (as in this example).



回答2:

Your callback should be something like:

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