C ++: Store a pointer to a member function of an object in another object

I have a class that calls a user-specified function in certain cases. Therefore, the class has a method void setExternalPostPaintFunction(void(*function)(QPainter&));

that can be used to "register" a function. Then this function will be called:

class A {
    public:
        void setExternalPostPaintFunction(void(*function)(QPainter&));
    private:
        void (*_externalPostPaint)(QPainter&);
        bool _externalPostPaintFunctionAssigned;
};

      

The function pointer is stored in a member variable _externalPostPaint

. The implementation setExternalPostPaintFunction

looks like this:

void A::setExternalPostPaintFunction(void(*function)(QPainter&)) {
    _externalPostPaint = function;
    _externalPostPaintFunctionAssigned = true;
}

      

This now works with normal functions. However, I also want to be able to pass pointers to member functions of objects. From what I know, I also need to pass and store a pointer to an object in this case. However, I don't know what type the other object will be. So I guess I am forced to use templates. I already thought about something like this:

class A {
    public:
        template <typename T>
        void setExternalPostPaintFunction(void(T::*function)(QPainter&), T* object);
    private:
        void (T::*_externalPostPaint)(QPainter&);       //<- This can't work!
        bool _externalPostPaintFunctionAssigned;
};

      

This way I can pass a function pointer and an object pointer setExternalPostPaintFunction

and can probably call a function on an object inside that function. But I cannot store it in a variable _externalPostPaint

because the type T

is inferred only when the function is called setExternalPostPaintFunction

, so I cannot have a member variable that depends on that type, since the type of my member variable must be known when the object is created, and besides Moreover, it cannot change, but it will occur when a new function is assigned, which may be a member function of an object of a different type.

So what's the correct way to do this, or not? I'm not very good with templates and function pointers, so I might be missing something.

The Anoter parameter should certainly have created a functor class with a virtual member function that can be overwritten in the derived class and then pass + store a pointer to an object of that type instead of a function pointer. But I would somehow prefer my approach if possible.

EDIT: SOLUTION

Tartan Llama got me on the right track by suggesting to use std::function

. This is how I solved it:

class A {
    public:
        template <typename T>
        void setExternalPostPaintFunction(T* object, void(T::*function)(QPainter&)) {
            _externalPostPaint = std::bind(function, object, std::placeholders::_1);
            _externalPostPaintFunctionAssigned = true;
        }
        void setExternalPostPaintFunction(std::function<void(QPainter&)> const& function);
    private:
        std::function<void(QPainter&)> _externalPostPaint;
        bool _externalPostPaintFunctionAssigned;
};

      

As you can see, the function / member pointer is now stored in the object std::function<void(QPainter&)>

. The advantage is that it std::function

can basically store any callable target. Then there are two overloads: one that can be used on any object std::function

that also accepts, eg. a normal function pointer (because the expected one is then std::function

implicitly constructed) and one for member functions to be called on the object (more for convenience). The latter is implemented as a template. This uses std::bind

to std::function

instantiate a call to this member function (user passed) on an object (user passed).

The overload that takes std::function

is implemented in the source file as follows:

void ImageView::setExternalPostPaintFunction(std::function<void(QPainter&)> const& function) {
    _externalPostPaint = function;
    _externalPostPaintFunctionAssigned = true;
}

      

Calling this stored function in class code is A

now simple:

//canvas is a QPainter instance    
if (_externalPostPaintFunctionAssigned) _externalPostPaint(canvas);

      

A user who wants to register a member function as a callback function should do the following:

//_imageView is an instance of "A"
//"MainInterface" is the type of "this"
_imageView->setExternalPostPaintFunction(this, &MainInterface::infoPaintFunction);

      

Or, if it's not a member function, but just a normal function:

void someFunction(QPainter& painter) {
    //do stuff
}

_imageView->setExternalPostPaintFunction(&someFunction);

      

Or he can explicitly create an object std::function

and pass it:

std::function<void(QPainter&)> function = [&](QPainter& painter){ this->infoPaintFunction(painter); };
_imageView->setExternalPostPaintFunction(function);

      

Works like a charm.

0


source to share


2 answers


You can use std::function

:

class A {
    public:
        //PostPaintFun can be anything which acts as a function taking a QPainter&
        //Could be a lambda, function pointer, functor, etc.
        using PostPaintFun = std::function<void(QPainter&)>;
        void setExternalPostPaintFunction(PostPaintFun fun);
    private:
        //Names beginning with an underscore are reserved, don't use them
        //Ending with an underscore is fine
        PostPaintFun fun_;
        bool externalPostPaintFunctionAssigned_;
};

      



Now you can use member functions like this:

struct B
{
    void exec(QPainter&) const;
};

void foo() {
    B b;
    a.setExternalPostPaintFunction(
        [b] (QPainter& p) {b.exec(p);}
    );
}

//or inside B
void B::foo() {
    a.setExternalPostPaintFunction(
        [this] (QPainter&p) {this->exec(p);}
    );
 }

      

+2


source


I have to say that I prefer Tartan Llama's answer, but here you have something that might work for you.

This may take some work, but I'm sure you get the idea.

struct IFunctionHolder {};                      // Used for pointing to any FunctionHolder
typedef IFunctionHolder* functionHolder_ptr;    // Alias for IFunctionHolder* .

template<typename Function>                     // The template for the actual function holders.
struct FunctionHolder:  public IFunctionHolder
{
    Function function;
};


class A {
    public:
        template <typename T>
        void setExternalPostPaintFunction(void(T::*function)(QPainter&), T* object);
    private:
        functionHolder_ptr *function_holder;            // This memeber can hold eny instantiation of template<> FunctionHolder.
                                                        // Instantiate this member wen calling setExternalPostPaintFunction
        bool _externalPostPaintFunctionAssigned;
};

      



You might have code like this:

A some_a;
void some_a.setExternalPostPaintFunction(&SomeInstance::some_fnunction);    // Here take place the instantiation of FunctionHolder.
some_a.function_holder.function(some_painter);

      

0


source







All Articles