Search code examples
c++structfunction-pointerspointer-to-member

C++ setting pointer to function member in a struct from outside the class


I try to set from outside the class the function pointers contained in the str struct within the class through the method SetPtr().

I get the error: invalid use of non-static member function.

class C {
    public:

    float v1, v2;

    struct S {
        float (*Read)();
        void  (*Write)(float);
    } str;

    float ReadV1() {
        return v1;
    }

    void WriteV1(float value) {
        v1 = value;
    }

    float ReadV2() {
        return v2;
    }

    void WriteV2(float value) {
        v2 = value;
    }

    void SetPtr(float (*read)(), void (*write)(float)) {
        str.Read = read;
        str.Write = write;
    }   

    void F()
    {
        float f = str.Read();
        str.Write(f);       
    }
};

int main()
{
    C c;

    c.SetPtr(c.ReadV1, c.WriteV2); // ERROR

    c.v1 = 0;
    c.F();
    return 0;
}

I also tried to replace function pointers by pointer to member functions:

class C {
    public:

    float v1, v2;

    struct S {
        float (C::*Read)();
        void  (C::*Write)(float);
    } str;

    float ReadV1() {
        return v1;
    }

    void WriteV1(float value) {
        v1 = value;
    }

    float ReadV2() {
        return v2;
    }

    void WriteV2(float value) {
        v2 = value;
    }

    void SetPtr(float (C::*read)(), void (C::*write)(float)) {
        str.Read = read;
        str.Write = write;
    }   

    void F()
    {
        float f = str.Read();   // ERROR
        str.Write(f);           // ERROR
    }
};

int main()
{
    C c;

    c.SetPtr(&C::ReadV1, &C::WriteV2);

    c.v1 = 0;
    c.F();
    return 0;
}

But this will move the error within the class:

error: must use ‘.’ or ‘->’ to call pointer-to-member function in ‘((C*)this)->C::str.C::S::Read (...)’, e.g. ‘(... ->* ((C*)this)->C::str.C::S::Read) (...)’

And whatever combination of this->, braces, *, ->, . I try, it doesn't work.

Any ideas? Thanks!


Solution

  • You need to use the second form (with pointer to class method), but when calling the methods you need to use:

    float f = (this->*str.Read)();
    (this->*str.Write) (f);
    

    The first method cannot work as it is because pointer to class method won't decay to pointer to standard function (i.e. float (C::*) () cannot decay to float (*) ()).

    With C++11 you could store the method as std::function and use std::bind:

    #include <functional>
    
    class C {
    
        struct S {
            std::function <float()> Read ;
            std::function <void(float)> Write ;
        } str ;
    
        void SetPtr(float (C::*read)(), void (C::*write)(float)) {
            str.Read = std::bind(read, this);
            str.Write = std::bind(write, this, std::placeholders::_1);
        }   
    
        void F() {
            float f = str.Read();
            str.Write (f);
        }
    
    }
    
    int main () {
        C c;
        c.SetPtr(&C::ReadV1, &C::WriteV2);
    }