Functor without warnings



  • Hi!
    There is a code in a Qt 5 project:

    class CActionFunctor
    {
    public:
        virtual ~CActionFunctor() { }
        virtual void operator()() = 0;
    };
    
    template <typename TClass>
    class TActionFunctor : public CActionFunctor
    {
    public:
        TActionFunctor(TClass *object, void(TClass::*function)())
        {
            Object = object;
            Function = function;
        }
    
        void operator()()
        {
            (*Object.*Function)();
        }
    
    private:
        TClass *Object;
        void (TClass::*Function)();
    };
    

    It generates warning:
    'CActionFunctor' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit

    Reading stackoverflow gives an idea that all virtual methods should be defined in *.cpp file.
    When I try to change *.h declaration to

    class CActionFunctor
    {
    public:
        virtual ~CActionFunctor();
        virtual void operator()();
    ...
    

    and add definition to *.cpp

    CActionFunctor::~CActionFunctor()
    {
    }
    
    void CActionFunctor::operator()()
    {
    }
    

    it generates error:
    undefined reference to `vtable for CActionFunctor'

    Could you please suggest how to solve this? Or point to a functor template that works well with Qt ?



  • You cannot mix templates and polymorphism IIRC.

    To be a tiny bit more complete, removing the virtual method would do, then you wouldn't need the mother class.



  • @JohanSolo I couldn't remove virtual-ness and the base class. The code above is located and the instance of the functor is declared and invoked in DLL

    CActionFunctor *SimulationInstanceChanged = nullptr;
    
    void CSimulation::Bind(CSimulation **simulation)
    {
        *simulation = this;
        (*SimulationInstanceChanged)();
    }
    

    while initialization is in the EXE

    extern CActionFunctor *SimulationInstanceChanged;
    
    WMain::WMain() {
        SimulationInstanceChanged = new TActionFunctor<WMain>(this, &WMain::OnSimulationInstanceChanged);
    }
    

    With this I can reformulate the question: is it possible to create a functor that can store and invoke an instance level function when type of the instance is not known in place of storage and invocation ?



  • @casperbear said in Functor without warnings:

    it generates error:
    undefined reference to `vtable for CActionFunctor'

    You have to dllexport CActionFunctor class, so that its vtable is available for use in external DLL (on Unix that works similarly in case you are using visibility attribute)

    @JohanSolo said in Functor without warnings:

    You cannot mix templates and polymorphism IIRC.

    Nothing prohibits that. Templates allow to replace some uses of run-time polymorphism with "static polymorphism" based on CRTP, but in most of real-world cases run-time polymorphism cannot be completely eleminated



  • @Konstantin-Tokarev It worked. Thank you. I had been looking at that warning for months. Final solution didn't require to move pure virtual function's definition to *.cpp. I'll leave it here for future seekers.
    DLL *.pro

    DEFINES += APPLICATIONMODEL_LIBRARY
    

    DLL and EXE *.h

    #ifdef APPLICATIONMODEL_LIBRARY
    # define APPLICATIONMODEL_EXPORT Q_DECL_EXPORT
    #else
    # define APPLICATIONMODEL_EXPORT Q_DECL_IMPORT
    #endif
    

    DLL *.h

    class APPLICATIONMODEL_EXPORT CActionFunctor
    {
    public:
        virtual ~CActionFunctor();
    
        virtual void operator()() = 0;
    };
    
    template <typename TClass>
    class TActionFunctor : public CActionFunctor
    {
    public:
        TActionFunctor(TClass *object, void(TClass::*function)())
        {
            Object = object;
            Function = function;
        }
    
        void operator()()
        {
            (*Object.*Function)();
        }
    
    private:
        TClass *Object;
        void (TClass::*Function)();
    };
    

    DDL *.cpp

    CActionFunctor::~CActionFunctor()
    {
    }
    
    APPLICATIONMODEL_EXPORT CActionFunctor *SimulationInstanceChanged = nullptr;
    
    void CSimulation::Bind(CSimulation **simulation)
    {
        *simulation = this;
        (*SimulationInstanceChanged)();
    }
    

    EXE *.cpp

    APPLICATIONMODEL_EXPORT CActionFunctor *SimulationInstanceChanged;
    
    WMain::WMain()
    {
        SimulationInstanceChanged = new TActionFunctor<WMain>(this, &WMain::OnSimulationInstanceChanged);
    }
    

 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.