Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. need help with pointer to member function

need help with pointer to member function

Scheduled Pinned Locked Moved Solved C++ Gurus
13 Posts 2 Posters 4.3k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    mzimmers
    wrote on 27 Apr 2018, 18:50 last edited by
    #1

    Hi all -

    I've been playing with this for awhile, and it's just beyond my journeyman C++ skills. Hopefully someone here can help out.

    I'm calling a routine that needs a function address as an argument. (It's xTaskCreate() in FreeRTOS.) I would greatly like to use a member function of a class for this. It's my understanding that I need to use a pointer to a member function, and a (non-member) wrapper for this pointer, to accomplish this. I think I have the pointer correct, but I can't properly code the wrapper.

    Here's what I'm trying:

    void (Wifi::*p)(QueueHandle_t queue) = &Wifi::test; 
    void wrapper(QueueHandle_t queue)
    {
        p(queue);
    }
    

    The "p(queue);" line produces an error. I've tried various forms of this, and nothing pleases the compiler. Can someone give me an idea of what I'm doing wrong?

    Thanks...

    K 1 Reply Last reply 27 Apr 2018, 19:12
    0
    • M mzimmers
      27 Apr 2018, 18:50

      Hi all -

      I've been playing with this for awhile, and it's just beyond my journeyman C++ skills. Hopefully someone here can help out.

      I'm calling a routine that needs a function address as an argument. (It's xTaskCreate() in FreeRTOS.) I would greatly like to use a member function of a class for this. It's my understanding that I need to use a pointer to a member function, and a (non-member) wrapper for this pointer, to accomplish this. I think I have the pointer correct, but I can't properly code the wrapper.

      Here's what I'm trying:

      void (Wifi::*p)(QueueHandle_t queue) = &Wifi::test; 
      void wrapper(QueueHandle_t queue)
      {
          p(queue);
      }
      

      The "p(queue);" line produces an error. I've tried various forms of this, and nothing pleases the compiler. Can someone give me an idea of what I'm doing wrong?

      Thanks...

      K Offline
      K Offline
      kshegunov
      Moderators
      wrote on 27 Apr 2018, 19:12 last edited by kshegunov
      #2

      @mzimmers said in need help with pointer to member function:

      The "p(queue);" line produces an error.

      Naturally. You don't have an object of type Wifi to call the method on. You'd need to call it like this (parentheses are not optional here, and are not an error):

      Wifi object;
      (object.*p)(queue);
      

      or

      Wifi * pointer;
      (pointer->*p)(queue);
      

      You can't call a non-static method without an object, or rather you should be careful that you don't ... :)

      Read and abide by the Qt Code of Conduct

      1 Reply Last reply
      4
      • M Offline
        M Offline
        mzimmers
        wrote on 27 Apr 2018, 20:00 last edited by
        #3

        Damn...it always looks so easy when you do it, kshegunov.

        If I understand this correctly, then:

        Wifi wifi;
        void wifiTaskWrapper(QueueHandle_t queue)
        {
            void (Wifi::*p)(QueueHandle_t queue) = &Wifi::wifi_task; 
            (wifi.*p)(queue);
        }
        

        p is a pointer to the wifi_task function within Wifi, and the object wifi gives it context. Yes?

        This is excellent. The only glitch is that I need to declare wifi as a global, but this is a small price to pay. Thanks for the help.

        K 1 Reply Last reply 27 Apr 2018, 20:07
        0
        • M mzimmers
          27 Apr 2018, 20:00

          Damn...it always looks so easy when you do it, kshegunov.

          If I understand this correctly, then:

          Wifi wifi;
          void wifiTaskWrapper(QueueHandle_t queue)
          {
              void (Wifi::*p)(QueueHandle_t queue) = &Wifi::wifi_task; 
              (wifi.*p)(queue);
          }
          

          p is a pointer to the wifi_task function within Wifi, and the object wifi gives it context. Yes?

          This is excellent. The only glitch is that I need to declare wifi as a global, but this is a small price to pay. Thanks for the help.

          K Offline
          K Offline
          kshegunov
          Moderators
          wrote on 27 Apr 2018, 20:07 last edited by
          #4

          @mzimmers said in need help with pointer to member function:

          Yes?

          Yes.

          The only glitch is that I need to declare wifi as a global, but this is a small price to pay.

          Actually, you don't. I've taken the liberty of looking up the documentation of xTaskCreate, which allows for context to be passed. So consider something like this:

          struct TaksParameters
          {
              Wifi wifi;
              QueueHandle_t queue;
          };
          
          void callback(void * data)
          {
              TaskParameters & parameters = *reinterpret_cast<TaksParameters *>(data);
              // Pure C magic ;)
          }
          

          Which you'd start as:

              TaksParameters parameters; // Or in the heap, I didn't go that far in the docs
              xTaskCreate(callback, ..., &parameters, ... /* More C goodness */);
          

          Read and abide by the Qt Code of Conduct

          1 Reply Last reply
          2
          • M Offline
            M Offline
            mzimmers
            wrote on 27 Apr 2018, 20:29 last edited by
            #5

            What does this line do?

            TaskParameters & parameters = *reinterpret_cast<TaksParameters *>(data);
            

            I see that it's distinct from the "parameters" declared outside of the function, so I'm not sure what its purpose is.

            K 1 Reply Last reply 27 Apr 2018, 20:52
            0
            • M mzimmers
              27 Apr 2018, 20:29

              What does this line do?

              TaskParameters & parameters = *reinterpret_cast<TaksParameters *>(data);
              

              I see that it's distinct from the "parameters" declared outside of the function, so I'm not sure what its purpose is.

              K Offline
              K Offline
              kshegunov
              Moderators
              wrote on 27 Apr 2018, 20:52 last edited by kshegunov
              #6

              void * is the so called opaque pointer, it means you hold an address to memory, but it doesn't specify what kind of data resides in that memory. As the data passed to xTaskCreate is of TaskParameters type, you know that your callback should be called with that data as argument. However, inside the function you must tell the compiler how to treat that data block, it doesn't know what is behind the void *. As you do, you tell it: "interpret the address to nothing (void *), as address to TaskParameters and don't ask any questions". reinterpret_cast doesn't expand to anything in the assembly (no instructions), it just tells the compiler that behind this particular address in memory there's an object of type TaskParameters.

              Read and abide by the Qt Code of Conduct

              1 Reply Last reply
              2
              • M Offline
                M Offline
                mzimmers
                wrote on 27 Apr 2018, 21:03 last edited by
                #7

                Thanks for the explanation. I was referring, though, to the declaration itself. I guess I don't understand what "TaskParameters & parameters" is, and how it relates to the structure created here:

                TaksParameters parameters; // Or in the heap, I didn't go that far in the docs
                
                K 1 Reply Last reply 27 Apr 2018, 21:06
                0
                • M mzimmers
                  27 Apr 2018, 21:03

                  Thanks for the explanation. I was referring, though, to the declaration itself. I guess I don't understand what "TaskParameters & parameters" is, and how it relates to the structure created here:

                  TaksParameters parameters; // Or in the heap, I didn't go that far in the docs
                  
                  K Offline
                  K Offline
                  kshegunov
                  Moderators
                  wrote on 27 Apr 2018, 21:06 last edited by kshegunov
                  #8

                  Ah, this you can ignore, it's simply a syntactic sugar of sorts to dereference the object (the * before the reinterpret_cast) to get an (l-value) reference. You can simply work with the pointer (and is probably better in this case, as I suspect you may be the one to free the memory in the end. I.e. you can simply substitute it with:

                  TaskParameters * parameters = reinterpret_cast<TaksParameters *>(data);
                  

                  Just converts the void * to TaksParameters *. And the void * points to a TaksParameters objects as per the xTaskCreate documentation, look at the pvParameters description here.

                  PS. And indeed, you should create the TaskParameters in the heap, not in the stack (as I conveniently missed in the docs), and delete the object at the end of your task.

                  Read and abide by the Qt Code of Conduct

                  1 Reply Last reply
                  1
                  • M Offline
                    M Offline
                    mzimmers
                    wrote on 27 Apr 2018, 21:25 last edited by mzimmers
                    #9

                    I can see that I'm doing a poor job of phrasing the question. Here's my understanding of your suggestion, in code:

                    struct TaskParams
                    {
                        Wifi wifi;
                        QueueHandle_t queue;
                    };
                    void wifiTaskWrapper(void * data)
                    {
                        TaskParams * params = reinterpret_cast<TaskParams *>(data);
                    }
                    void app_main()
                    {
                    ...
                        TaskParams params; 
                        xTaskCreate(wifiTaskWrapper, "wifi_task", 4096, params, 5, &h);
                    }
                    

                    This obviously won't work, because the params structure in app_main() isn't initialized. How does the pointer you create end up pointing to this value?

                    K 1 Reply Last reply 27 Apr 2018, 21:34
                    0
                    • M mzimmers
                      27 Apr 2018, 21:25

                      I can see that I'm doing a poor job of phrasing the question. Here's my understanding of your suggestion, in code:

                      struct TaskParams
                      {
                          Wifi wifi;
                          QueueHandle_t queue;
                      };
                      void wifiTaskWrapper(void * data)
                      {
                          TaskParams * params = reinterpret_cast<TaskParams *>(data);
                      }
                      void app_main()
                      {
                      ...
                          TaskParams params; 
                          xTaskCreate(wifiTaskWrapper, "wifi_task", 4096, params, 5, &h);
                      }
                      

                      This obviously won't work, because the params structure in app_main() isn't initialized. How does the pointer you create end up pointing to this value?

                      K Offline
                      K Offline
                      kshegunov
                      Moderators
                      wrote on 27 Apr 2018, 21:34 last edited by
                      #10

                      @mzimmers said in need help with pointer to member function:

                      How does the pointer you create end up pointing to this value?

                      I specifically requested the address:

                       xTaskCreate(callback, ..., &parameters, ... /* More C goodness */);
                      

                      Notice the &?
                      Then xTaskCreate will call callback at the appropriate time with the pointer I passed it as an argument.

                      However, consider the following updated/corrected suggestion:

                      struct TaskParams
                      {
                          Wifi wifi;
                          QueueHandle_t queue;
                      };
                      
                      void callback(void * data)
                      {
                          TaskParams * params = reinterpret_cast<TaskParams *>(data);
                      }
                      
                      void app_main()
                      {
                      ...
                          TaskParams * params = new TaskParams(); //< As mentioned you need to create it in the heap.
                          // Here it's your job to initialize it :)
                      
                          xTaskCreate(wifiTaskWrapper, "wifi_task", 4096, params, 5, &h); //< You pass it to `xTaskCreate`, which will pass it to your `wifiTaskWrapper` function when it calls it.
                      }
                      

                      Read and abide by the Qt Code of Conduct

                      1 Reply Last reply
                      0
                      • M Offline
                        M Offline
                        mzimmers
                        wrote on 27 Apr 2018, 22:14 last edited by
                        #11

                        OK, I'm getting this bit by bit. So, if my program looks like this:

                        struct TaskParams
                        {
                            Wifi wifi;
                            QueueHandle_t q;
                        };
                        void testTaskWrapper(void *data)
                        {
                            TaskParams *params = reinterpret_cast<TaskParams *>(data);
                        }
                        void app_main()
                        {
                            Wifi wifiObj;
                            TaskParams *params = new TaskParams();
                            params->wifi = ???;
                            
                            xTaskCreate(testTaskWrapper, "wifi_task", 4096, params, 5, &wifiTaskHandle);
                        

                        What is the correct syntax for the Wifi member of the params struct? And where do I point it to the routine wifi_task?

                        K 1 Reply Last reply 28 Apr 2018, 07:46
                        0
                        • M mzimmers
                          27 Apr 2018, 22:14

                          OK, I'm getting this bit by bit. So, if my program looks like this:

                          struct TaskParams
                          {
                              Wifi wifi;
                              QueueHandle_t q;
                          };
                          void testTaskWrapper(void *data)
                          {
                              TaskParams *params = reinterpret_cast<TaskParams *>(data);
                          }
                          void app_main()
                          {
                              Wifi wifiObj;
                              TaskParams *params = new TaskParams();
                              params->wifi = ???;
                              
                              xTaskCreate(testTaskWrapper, "wifi_task", 4096, params, 5, &wifiTaskHandle);
                          

                          What is the correct syntax for the Wifi member of the params struct? And where do I point it to the routine wifi_task?

                          K Offline
                          K Offline
                          kshegunov
                          Moderators
                          wrote on 28 Apr 2018, 07:46 last edited by kshegunov
                          #12

                          @mzimmers said in need help with pointer to member function:

                          What is the correct syntax for the Wifi member of the params struct?

                          Well, it's the wifi object itself. It will be created when you create the TaskParams instance, but you could also create it in the heap:

                          struct TaskParams
                          {
                              Wifi * wifi;
                              QueueHandle_t q;
                          };
                          
                          void app_main()
                          {
                              TaskParams *params = new TaskParams();
                              params->wifi = new Wifi( ... );
                              // ....
                          }
                          

                          If it's copyable data type, you can also directly assign it:

                          struct TaskParams
                          {
                              Wifi wifi;
                              QueueHandle_t q;
                          };
                          
                          TaskParams * params = new TaskParams();
                          Wifi wifiObj;
                          params->wifi = wifiObj;
                          

                          And where do I point it to the routine wifi_task?

                          You don't, you can call that method directly, you don't really need to store a pointer to member:

                          void testTaskWrapper(void *data)
                          {
                              TaskParams * params = reinterpret_cast<TaskParams *>(data);
                              params->wifi->wifi_task();
                          }
                          

                          The idea is to pack all the arguments you task function needs into one variable. To that end you could also use a std::tuple if you don't like the idea of defining your own struct; it'd work the same way.

                          Read and abide by the Qt Code of Conduct

                          1 Reply Last reply
                          3
                          • M Offline
                            M Offline
                            mzimmers
                            wrote on 30 Apr 2018, 20:02 last edited by
                            #13

                            Well, that's some pretty fancy stuff. Thanks for the explanation(s)...this will be very useful.

                            1 Reply Last reply
                            0

                            2/13

                            27 Apr 2018, 19:12

                            topic:navigator.unread, 11
                            • Login

                            • Login or register to search.
                            2 out of 13
                            • First post
                              2/13
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved