Search code examples
c++function-pointers

How can I pass a member function into C-style function pointers from an old API


I'm working with a data provider which offered a C-style API. It expects my data handler function to be provided as a function pointer. I'm trying to encapsulate my end of the logic in a class with the handler being a member function. I'm not sure how to do it. Code snippet below shows my dilemma.

extern "C" 
{
    /**
     * This is part of my data provider's C API (which I cannot change)
     * It asks me to put my data handler in a function, then register
     * it as a C-style function pointer.
     */
    void set_update_callback(void (*p)(struct Data *));
}


/** I tried to encapsulate this data service within a class */
class MyDataClass
{
  private:

    /** Data should pushed to this queue.
     * The queue is created outside my class, then its pointer is passed in from the constructor (below)
     */
    queue<DataParsed>* _data_out_queue;

  public:
    MyDataClass(queue<DataParsed>* data_out_queue): _data_out_queue(data_out_queue) {}

    /** Subscribe to the data provider using my handler function */
    void subscribe()
    {
      set_update_callback(handle_data);
    }

    /** 
     * This handler function is where the dilemma is:
     * - It needs to be static because it needs to be converted to a plain C-style function pointer
     * - It needs to be non-static because it needs to write to the member object _data_out_queue
     */
    static void handle_data(struct Data *d)
    {
      // parse data from *d and push into _data_out_queue
    }
}

I'm trying to find a clean C++ solution and not putting anything in the global space. Any guidance appreciated!


Solution

  • You can only do this if you have only one instance of MyDataClass e.g.

    extern "C" 
    {
        struct Data
        {
            const char* data;
        };
    
        /**
         * This is part of my data provider's C API (which I cannot change)
         * It asks me to put my data handler in a function, then register
         * it as a C-style function pointer.
         */
        void set_update_callback(void (*p)(struct Data *));
    }
    
    #include <queue>
    
    struct DataParsed
    {
        int data;
    };
    
    
    /** I tried to encapsulate this data service within a class */
    class MyDataClass
    {
      public:
        static MyDataClass& GetInstanceAndSubscribe()
        {
            static std::queue<DataParsed> data_out_queue;
            static MyDataClass instance(data_out_queue);
            set_update_callback(handle_data);
            return instance;
        }
    
      private:
         MyDataClass(std::queue<DataParsed>& data_out_queue): _data_out_queue(data_out_queue) {}
    
         /** 
         * This handler function is where the dilemma is:
         * - It needs to be static because it needs to be converted to a plain C-style function pointer
         * - It needs to be non-static because it needs to write to the member object _data_out_queue
         */
        static void handle_data(struct Data *d)
        {
          // parse data from *d and push into _data_out_queue
        }
    
        /** Data should pushed to this queue.
         * The queue is created outside my class, then its pointer is passed in from the constructor (below)
         */
        std::queue<DataParsed>& _data_out_queue;
    };
    
    int main()
    {
        auto& my_data_class = MyDataClass::GetInstanceAndSubscribe();
        
    }