Search code examples
c++pointer-to-memberavr-gcc

Provide a pointer to member function to be invoked by the target class without functional


I'm reading a lot of questions (and answers) about function pointers, functors and callbacks but I still have a confusion about which is the right tool for me.

Some of them cannot apply to my scenario because it seems my compiler avr-gcc v5.4.0 does not have C++ standard library (i.e. std::function is not available).

This is my base class:

class Debouncer
{
public:
    typedef uint8_t (Debouncer::*debouncer_raw_t) (void);

    Debouncer() {}
    void setRawFunction(Debouncer::debouncer_raw_t callback) { _raw = callback; }

private:
    debouncer_raw_t _raw;
    void anotherFunction()
    {
        uint8_t value = _raw();
        // do something
    }
}

In my other classes I have:

class Inputs
{
public:
    Inputs()
    {
        _deb.setRawFunction(myRaw);
    }

private:
    Debouncer _deb;
    uint8_t myRaw()
    {
        return something;
    }
}

Of course this won't compile because myRaw is not static. Anyway, I'm going to try to avoid this because it would break the existing code.

If I'm not wrong, a lot of questions seem to ask the other way around. Instead I just want to pass the pointer of my member function to my Debouncer class, so it can call _raw() when it needs to.

Here I found this advise to avoid std:: library:

#define CALL_MEMBER_FN(object, ptrToMember)  ((object).*(ptrToMember))

void userCode(Fred& fred, FredMemFn p)  // Use a typedef for pointer-to-member types
{
  int ans = CALL_MEMBER_FN(fred,p)('x', 3.14);
  // Would normally be: int ans = (fred.*p)('x', 3.14);
  // ...
}

But it seems the other way around. Here the class Fred is my Debouncer. I don't want to call the Debouncer member, but member of the caller class (i.e. Input::myRaw()).

Would you please help me to understand which is the right tool to achieve such a simple task?


Solution

  • Making a member function virtual is a relatively low-overhead way to have a single pointer (to an object) refer to both the object's data and the correct member function.

    class InputsBase
    {
        // All classes that implement myRaw() should inherit from this class
    public:
        virtual uint8_t myRaw() = 0;
    };
    
    class Inputs : public InputsBase
    {
    public:
        Inputs()
        {
            _deb.setRawFunction(this);
        }
    
    private:
        Debouncer _deb;
        virtual uint8_t myRaw()
        {
            return something;
        }
    }
    

    Your Debouncer can then simply store a pointer to the object in question.

    class Debouncer
    {
    public:
        typedef InputsBase* debouncer_raw_t;
    
        Debouncer() {}
        void setRawFunction(debouncer_raw_t callback) { _raw = callback; }
    
    private:
        debouncer_raw_t _raw;
        void anotherFunction()
        {
            uint8_t value = _raw->myRaw();
            // do something
        }
    }