0

I am trying pass the function as an argument, the Testabc is inherited from MainTest and the function I want to pass is protected function in MainTest class. I do not have the cpp access to the MainTest class which has this protected ReadTestPoint function.

Below is header file where I define the function that is taking the function as an argument.

#include <QObject>
#include <QDebug>

class TestManager
{
 public:
 TestManager();
~TestManager() {}
int ReadTestPointer(void *dp, unsigned int &val, int (*functioncall)(void *, 
unsigned int&));
};

Below is the cpp for the TestManager

#include "testmanager.h"
#include<QDebug>
TestManager::TestManager(){}

int TestManager::ReadTestPointer(void* dp, unsigned int &num, int (*readt)
(void*, unsigned int&))
{
   qDebug()<< "Function Pointer working";
   int g;
   g = (*readt)(dp, num);
   return g;
}

The class from where I am making the call:

 namespace PackageCore
 {

 TestAbc::TestAbc() : MainTest(){}
 TestAbc::~TestAbc(){}

 int TestAbc::Init()
 {
  // initialization code called once
   m_config = reinterpret_cast<Test_BaseClass*>
   (GetConfig(Test_BaseClass_INTERFACE_HASH));
  return 0;
}
int TestAbc::DeInit()
{
   return 0;
}

int TestAbc::Cycle()
{
   TestManager m_TestManager;
   unsigned int m_trigger;
   int (*abc)(void *, unsigned int&) = ReadTestPoint(m_config-
    >SHM_B_Trigger_U8, m_trigger);
   m_TestManager.ReadTestPointer(m_config->SHM_B_Trigger_U8, m_trigger, abc);
   qDebug()<< " getTrigger: " << m_trigger;
   return 0;
}
}

But I get the compile time error on this:

C:\test_manager_git\testabc.cpp:39: error: invalid conversion from 'int' to 'int (*)(void*, unsigned int&)' [-fpermissive]
 int (*abc)(void *, unsigned int&) = ReadTestPoint(m_config->SHM_B_Trigger_U8, m_trigger);
                                                                                            The MainTest.h is below:
   class MainTest : public QObject
  {
   Q_OBJECT

   public:

    // Callbacks
    virtual int Init() = 0;
    virtual int Cycle() = 0;
    virtual int DeInit() = 0;

   protected:


     int ReadTestPoint (void *dp, unsigned int &val);


 };

Thanks

JNI_OnLoad
  • 5,472
  • 4
  • 35
  • 60
  • 2
    `ReadTestPoint(m_config->SHM_B_Trigger_U8, m_trigger);` is a function *call* (which apparently returns an `int` based on the error message), you cannot assign it to a function *pointer*. Simply removing the `abc` definition and passing `ReadTestPoint` directly into `ReadTestPointer` should compile fine – UnholySheep Jan 05 '18 at 07:36
  • I tried and still exactly the same error .. I tried like below: m_TestManager.ReadTestPointer(m_config->SHM_B_Trigger_U8, m_trigger, ReadTestPoint(m_config- >SHM_B_Trigger_U8, m_trigger)); – JNI_OnLoad Jan 05 '18 at 07:38
  • 2
    You are still trying to call the `ReadTestPoint` function directly instead of passing it as a function pointer - the correct syntax is `m_TestManager.ReadTestPointer(m_config->SHM_B_Trigger_U8, m_trigger, ReadTestPoint);` (remove the parentheses and arguments after `ReadTestPoint` – UnholySheep Jan 05 '18 at 07:39
  • aha ok, but now it throws error with no matching function like below: C:\test_manager_git\testabc.cpp:40: error: no matching function for call to 'TestManager ::ReadTestPointer(cfgObj::Dp*&, unsigned int&, )' m_TestManager.ReadTestPointer(m_config->SHM_B_Trigger_U8, m_trigger, ReadTestPoint); – JNI_OnLoad Jan 05 '18 at 07:42
  • Is `ReadTestPointer` a non-`static` member function? In that case you need to change the definition of the function pointer parameter, see https://stackoverflow.com/questions/2402579/function-pointer-to-member-function – UnholySheep Jan 05 '18 at 07:44
  • What is ReadTestPoint? Don't see it defined anywhere. – n. m. could be an AI Jan 05 '18 at 07:45
  • 1
    Please add the declaration of `ReadTestPoint` to your question instead of having us guess it. – grek40 Jan 05 '18 at 07:45
  • I said in the question as I do not have access to the cpp file that has the definition of ReadTestPoint.. it is a constraint .. I understand – JNI_OnLoad Jan 05 '18 at 07:47
  • But the class definition of `MainTest` and the member function declaration (not definition) of `ReadTestPoint` should be in a header file right? – grek40 Jan 05 '18 at 07:52
  • Yes, that I have the declaration of the ReadTestPoint in MainTest.h, I update now.. 1 min – JNI_OnLoad Jan 05 '18 at 07:54
  • Updated the MainTest.h – JNI_OnLoad Jan 05 '18 at 08:02
  • 2
    Consider using [`std::function`](http://en.cppreference.com/w/cpp/utility/functional/function) and [lambda expression](http://en.cppreference.com/w/cpp/language/lambda)s. Be aware of [closure](https://en.wikipedia.org/wiki/Closure_(computer_programming))s. For your next question, provide some [MCVE] – Basile Starynkevitch Jan 05 '18 at 08:06
  • There's about a zillion duplicates here, I can't be bothered to find the best one, search for "how to pass a member function as a callback" or something. – n. m. could be an AI Jan 05 '18 at 09:03

1 Answers1

0

First of all, consider using things like std::function instead of rolling your own pointer nightmare. But lets get started...

Basically, in order to call a member function from pointer, you need the function pointer and a member instance. The following code is based on your question code with the added member pointer.

#include <iostream>


class MainTest
{
public:

protected:
    int ReadTestPoint (void *dp, unsigned int &val)
    {
        std::cout << "protected ReadTestPoint called" << std::endl;
        return 0;
    }
};



class TestManager
{
public:
    TestManager() {}
    ~TestManager() {}
    int ReadTestPointer(void *dp, unsigned int &val, MainTest* instance, int (MainTest::*functioncall)(void *, unsigned int&))
    {
        return (instance->*functioncall)(dp, val);
    }
};


class TestAbc : public MainTest
{
public:
    void ExecTest()
    {
        TestManager testManager;
        unsigned int tVal;
        void* dummy = &tVal;

        testManager.ReadTestPointer(dummy, tVal, this, &TestAbc::ReadTestPoint);
    }
};


int main(void)
{
    TestAbc test;
    test.ExecTest();

    return 0;
}

If you don't want to restrict yourself to a specific member type, consider using a template function:

class TestManager
{
public:
    TestManager() {}
    ~TestManager() {}

    template<typename Fn>
    int ReadTestPointer(void *dp, unsigned int &val, Fn functioncall)
    {
        return functioncall(dp, val);
    }
};

It will accept non-member functions and objects that overload the operator() with appropriate parameters and return types.

You can wrap the member function pointer in a Functor object:

template<typename TMember, typename TResult, typename TParam1, typename TParam2>
struct Functor
{
    typedef TResult (TMember::*TFn)(TParam1, TParam2);

    Functor(TMember* m, TFn func):member(m), fn(func){}

    TMember* member;
    TFn fn;

    TResult operator()(TParam1 p1, TParam2 p2)
    {
        return (member->*fn)(p1, p2);
    }
};

The following example includes a free function call and a member function call:

int FreeFn(void *dp, unsigned int &val)
{
    std::cout << "free function called" << std::endl;
    return 1;
}


class TestAbc : public MainTest
{
public:
    void ExecTest()
    {
        TestManager testManager;
        unsigned int tVal;
        void* dummy = &tVal;

        testManager.ReadTestPointer(dummy, tVal, Functor<TestAbc, int, void*, unsigned int&>(this, &TestAbc::ReadTestPoint));

        testManager.ReadTestPointer(dummy, tVal, FreeFn);
    }
};
grek40
  • 13,113
  • 1
  • 24
  • 50