c++arduino

Create and execute a dynamic function pointer list from different instantiated class members (Arduino c++11)


I am using Arduino C++11

I want to create and execute a dynamically function pointer list from different instantiated class members. A function holding the dynamic list of funtion pointerns is called in the main program. I have tried several solutions, but I am stuck.

I hope the the framework below is sufficient documentation. If not please let me know.

class base {
// base class for holding global static functions. Shall not be instatited.
// if necessary, change class to namespace or struct.
  private:
    friend class class_inp;
    friend class class_out;
    static void base_add_funtion_pointer_from_instatiated_class_member 
    (/* function pointer upddate_event_control() */) {
      // what do do?
    }
  public:
    static void execute_dynamic_list_of_instatiated_function_pointers() {
      // how to do it?
    }
};

Two class with identical functions to call

class class_inp : public base {
  public:
    class_inp (bool eventSwitch) {
      base_add_funtion_pointer_from_instatiated_class_member
        (/* function pointer from upddate_event_control() */);
    }
    void upddate_event_control();
};
class class_out : public base {
  public:
    class_out (/* arguments*/) {
      base_add_funtion_pointer_from_instatiated_class_member
        (/* function pointer from upddate_event_control() */);
    }
    void upddate_event_control();
};

Main program

class_inp inp;
class_out out;

// Arduino main
void loop() {
  base::execute_dynamic_list_of_instatiated_function_pointers();
  delay(1); // waith 1 millisecond
}

Solution

  • you want to avoid dynamic allocations on embedded devices, but you can have linked lists. basically each object will contain a next pointer, and will register itself in the constructor.

    class base {
        // base class for holding global static functions. Shall not be instatited.
        // if necessary, change class to namespace or struct.
        private:
            friend class class_inp;
            friend class class_out;
            static void base_add_funtion_pointer_from_instatiated_class_member 
            (base* object) {
                if (begin == nullptr)
                {
                    begin = object;
                }
                if (end != nullptr)
                {
                    end->next = object;
                }
                end = object;
            }
            static base* begin;
            static base* end;
            base* next = nullptr;
        protected:
        virtual void update_event_control() = 0;
        public:
            base(const base&) = delete;
            base& operator=(const base&) = delete;
            base() {}
            
            static void execute_dynamic_list_of_instatiated_function_pointers() {
                base* object = begin;
                while (object != nullptr)
                {
                    object->update_event_control();
                    object = object->next;
                }
            }
    };
    // make sure those two are in a .cpp file
    base* base::begin = nullptr;
    base* base::end = nullptr;
    
    class class_inp : public base {
      public:
        class_inp (bool eventSwitch = false) {
          base_add_funtion_pointer_from_instatiated_class_member(this);
        }
        void update_event_control() override {
            std::cout << "inp\n";
        }
    };
    

    online demo

    improvements for future if needed: unregister the object in the destructor.

    if only 1 member function is ever needed, you can remove virtual and store a function pointer, this removes a few cycles (3 instructions per call), this is not needed for a computer but may make a difference on a microcontroller.

    class base {
        // base class for holding global static functions. Shall not be instatited.
        // if necessary, change class to namespace or struct.
        private:
            friend class class_inp;
            friend class class_out;
            static void base_add_funtion_pointer_from_instatiated_class_member 
            (base* object) {
                if (begin == nullptr)
                {
                    begin = object;
                }
                if (end != nullptr)
                {
                    end->next = object;
                }
                end = object;
            }
            static base* begin;
            static base* end;
            base* next = nullptr;
            using func_type = void (*)(base*);
            func_type func = nullptr;
        public:
            base(const base&) = delete;
            base& operator=(const base&) = delete;
            base(func_type f) : func{f} {}
    
            static void execute_dynamic_list_of_instatiated_function_pointers() {
                base* object = begin;
                while (object != nullptr)
                {
                    object->func(object);
                    object = object->next;
                }
            }
    };
    // make sure those two are in a .cpp file
    base* base::begin = nullptr;
    base* base::end = nullptr;
    
    class class_inp : public base {
      public:
        class_inp (bool eventSwitch = false)
        :base{[](base* p) { static_cast<class_inp*>(p)->update_event_control(); }}
        {
          base_add_funtion_pointer_from_instatiated_class_member(this);
        }
        void update_event_control() {
            std::cout << "inp\n";
        }
    };
    

    online demo