I have 2 functions with the same input and output types.
uint32_t doWork(uint32_t time);
uint32_t MyClass::DoWork(uint32_t time);
now I want to dependency inject this function into another class to either use one of the functions.
So I thought I could use a function point but this is not working since a function pointer requires the class type to also be used.
Is there any way to store both functions in the same function pointer type and pass it to a constructor?
The function from the class is not static.
Any help is appreciated!
I experimented a little bit with my C++ compiler.
Here is what I got that seems to be doing the job:
#include <stdio.h>
typedef unsigned int uint32_t;
typedef uint32_t (doWorkPtr) (uint32_t time);
uint32_t doWork(uint32_t time) {
return time*2;
}
class MyClass {
public:
int times;
int DoWork(uint32_t time) { return time*times; }
};
struct Adapter {
MyClass* a;
doWorkPtr* ptr;
int operator() (uint32_t time) {
if(a)
return a->DoWork(time);
else
return ptr(time);
}
};
int main(int argc, char** argv) {
Adapter* pointers[2];
MyClass klass;
klass.times = 3;
Adapter adapter;
adapter.a = &klass;
adapter.ptr = 0;
Adapter adapter2;
adapter2.a = 0;
adapter2.ptr = &doWork;
pointers[0] = &adapter;
pointers[1] = &adapter2;
printf("result1 %i\n", (*pointers[0])(1));
printf("result2 %i\n", (*pointers[1])(1));
return 0;
}
Your class would store 'Adapter' pointers instead of plain functions pointers when using this.
Hope it helps!
Related
I'm deriving a class from a base class outside my control. The class will get created by a factory function pointer I pass in (in a part of the code I also don't control).
In my derived class, I need to pass an additional constructor argument to the factory function.
My first stab was to try to adapt the factory function via a lambda, but that cannot capture the additional argument. Other answers explained why that doesn't work. Next I've tried to augment that with std::function which other answers have led me to believe would work, but I can't figure out the right syntax and have found the examples to be incomprehensible (and not sure I really understand what that is even doing).
What am I doing wrong here? Is there a better way to solve this?
Demonstration code:
#include <functional>
#include <string>
// I have no control over this
struct Base {
Base(int i) {}
};
void UseObject(Base *(*factory)(int i)) {
Base *instance = factory(5);
// Save created instance
}
// I control the rest
struct Derived : public Base {
Derived(const char *s, int i) : Base(i) { /* Store s for later use */ }
static Base *Factory(const char *s, int i) { return new Derived(s, i); }
};
void AddObject(const char *name)
{
// First stab
// UseObject([name] (int i) { return Derived::Factory(name, i); });
// Second stab
std::function<Base *(int i)> foo { [name] (int i) { return Derived::Factory(name, i); } };
UseObject(foo);
}
int main(int ac, char **av)
{
AddObject("some_name");
AddObject("another_name");
return 0;
}
The error I get from g++ (7.4.0) is:
tfunc.cpp: In function ‘void AddObject(const char*)’:
tfunc.cpp:28:18: error: cannot convert ‘std::function<Base*(int)>’ to ‘Base* (*)(int)’ for argument ‘1’ to ‘void UseObject(Base* (*)(int))’
UseObject(foo);
UseObject doesn't allow non capturing lambda or std::function or regular class functor. The only callable it accepts is function pointer (non capturing lambda can convert to).
So you might do:
UseObject([](int i) { return Derived::Factory("some_name", i); });
but not
auto name = "some_name";
UseObject([name] (int i) { return Derived::Factory(name, i); });
Possible (limited) workaround is to use global variable to store state. (So cannot be used concurrently).
void AddObject(const char *name)
{
// global usage as UseObject only accepts pointer function
static const char* instance = nullptr;
instance = name;
UseObject(+[](int i) { return Derived::Factory(instance, i); });
}
I am trying to create a dynamic function pointer that points to some methods all the methods I want to save on the array return a bool and have an uint32_t parameter. The functions are Service functions. These are intended to be dynamic, so when a class is started, the constructor links the service function from the object to be called from outside the object.
With the code below I am getting the following error:
Build error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.
I have no clue what to do to overcome this problem, any idea would be greatly appreciated, thanks!
//File 1
typedef bool (*ServiceFunctionsType)(uint32_t);
//File 2
#include "File1.hpp"
extern uint8_t ServiceFunctions_size;
extern ServiceFunctionsType *ServiceFunctions;
void Service_Functions_Setup();
bool SetPtr(ServiceFunctionsType a);
void ClearPtr(uint8_t id);
//File 3
#include "File1.hpp"
ServiceFunctionsType *ServiceFunctions;
uint8_t ServiceFunctions_size = 0;
//File 4
#include "File2.hpp"
#include <stdlib.h>
void Service_Functions_Setup()
{
ServiceFunctions = NULL;
if(SERVICE_FUNCTION_POINTER_START_SIZE != 0)
{
ServiceFunctions_size = SERVICE_FUNCTION_POINTER_START_SIZE;
ServiceFunctions = (ServiceFunctionsType*)malloc(sizeof(ServiceFunctionsType)*SERVICE_FUNCTION_POINTER_START_SIZE);
for(uint8_t i = 0; i < SERVICE_FUNCTION_POINTER_START_SIZE; i++)
{
ServiceFunctions[i] = NULL;
}
}
}
uint8_t SetServiceFunctionPointer(ServiceFunctionsType a, bool _realloc)
{
if( ServiceFunctions == NULL )
{
ServiceFunctions = (ServiceFunctionsType*)malloc(sizeof(ServiceFunctionsType));
ServiceFunctions[0] = a;
return 0;
}
for(uint8_t i = 0; i < ServiceFunctions_size; i++)
{
if( ServiceFunctions[i] == NULL )
{
ServiceFunctions[i] = a;
return i;
}
}
if(_realloc)
{
ServiceFunctions_size++;
ServiceFunctions = (ServiceFunctionsType*)realloc(ServiceFunctions,sizeof(ServiceFunctionsType)*ServiceFunctions_size);
ServiceFunctions[ServiceFunctions_size - 1] = a;
return ServiceFunctions_size - 1;
}
return INVALID_SERVICE_FUNCTION_POINTER;
}
void ClearServiceFunctionPointer(uint8_t id)
{
ServiceFunctions[id] = NULL;
}
//File 5
class MonoStepSequencer
{
public:
MonoStepSequencer();
~MonoStepSequencer();
uint8_t ServicePointerID;
bool Service(uint32_t time);
private:
};
//File 6
#include "File2.hpp"
MonoStepSequencer::MonoStepSequencer()
{
ServicePointerID = SetServiceFunctionPointer(&this -> Service);
}
//This is the function to be called with a pointer
bool MonoStepSequencer::Service(uint32_t time)
{
//Some Code
}
You can try, to use lambdas. Create method like
std::function<void()> getService()
Where inside you can use:
return [this](){
Service();
};
Also if your methods should use arguments, you can use this method, but add arguments into return value and lambda.
One more, you can create lambda outside of class methods, like:
[&object]()
{
object.Service();
}
In this way, better to use std::shared_ptr to guаrantee that object exists, when lambda called.
this -> Service is an unqualified or parenthesized non-static member function
You probably meant :: instead of -> Also, you need a type on the left, not a variable.
Also, please don't put spaces around ->. That makes it look like you're specifying a trailing return type or something.
i was wondering if is possible make that a method of class points to another method of other class:
consider this:
// Class Foo:
class Foo
{
static int GetA(int a);
static int GetB(int b);
};
int Foo::GetA(int a)
{
return a * 2;
}
int Foo::GetB(int b)
{
return a * 4;
}
// Hooking class methods:
class HookFoo
{
static int HookGetA(int);
static int HookGetB(int);
};
int(HookFoo::*HookGetA)(int) = (int(HookFoo::*)(int))0x0; // (0x0 Memory address) or for example: &Foo::GetA;
int(HookFoo::*HookGetB)(int) = (int(HookFoo::*)(int))0x0; // (0x0 Memory address) or for example: &Foo::GetA;
I know it's possible do some like:
int(*NewHook)(int) = &Foo::GetA;
but how i can do for declare the methods into of a class?
Here is more or less what you tried to achieve (minimal, working example):
class Foo
{
public:
static int GetA(int a);
static int GetB(int b);
};
int Foo::GetA(int a)
{
return a * 2;
}
int Foo::GetB(int b)
{
return b * 4;
}
class HookFoo
{
public:
using FuncType = int(*)(int);
static FuncType HookGetA;
static FuncType HookGetB;
};
// Initialized with Foo::GetA
HookFoo::FuncType HookFoo::HookGetA = &Foo::GetA;
// nullptr'ed
HookFoo::FuncType HookFoo::HookGetB = nullptr;
int main() {
HookFoo::HookGetA(0);
}
For the methods in Foo are static, you can use a simple function pointer type to refer to them. You don't have to use (and can't use actually) a member function pointer in this case.
The using declaration helps to have a more readable code.
When you have correctly initialized your hooks, you can invoke them (thus the pointed functions) as you can see in the main.
I added a couple of visibility specifiers for your methods and data members were all private.
You can use function pointers.
Ex:
class A {
public:
static void say_hello() { cout << "Hello\n"; }
};
class B {
public:
static void(*hook)();
};
void(*B::hook)() = A::say_hello;
int main()
{
B::hook();
}
If you need to hook into functions at a specific address, use a function pointer. You can't reassign functions like that
// typedef your function pointers, it makes the syntax a lot easier
typedef int(*FHook)(int);
class HookFoo
{
static FHook HookGetA;
static FHook HookGetB;
};
// assign to address
FHook HookFoo::HookGetA = (FHook)0x1234;
FHook HookFoo::HookGetB = (FHook)0x5678;
Of course its your job to make sure the addresses are correct.
the explicit function pointer types would be as such:
class HookFoo
{
static int (*HookGetA)(int);
static int (*HookGetB)(int);
};
int (*HookFoo::HookGetA)(int) = (int(*)(int))0x1234;
int (*HookFoo::HookGetB)(int) = (int(*)(int))0x5678;
I have class
Class A{
};
typedef struct
{
const char *dec_text;
void (A::*TestFun)();
} Test ;
Test _funs[] = {{"testLogOK", &A::testLogOK},
{"testLoginException", &A::testLoginException}
};;
How can i initialize this Test Array in construct method. The _funs tracks the A's method name and corresponding address, the methods which like:
void (methodName) (void)
In construction method, both below ways fail:
_funs = {{"testLogOK", &A::testLogOK},
{"testLoginException", &A::testLoginException}
};
The other question is how can i invoke the function pointer.. I tried the way like:
int
A::run (const char *name, int argc, ACE_TCHAR *argv[])
{
for(int i=0; i< sizeof(_funs)/sizeof(Test); i++){
Test test = _funs[i];
*(test.testFun)(); //this->*(test.fun)(); Both fail with same error
//(this->*(test.fun))() works
}
}
The compile also fails with message:
error C2064: term does not evaluate to a function taking 0 arguments
[UPdate]
I removed the struct Test and Test _funs out of Class A. But still have problem in A's method:
int A::run (const char *name, int argc, ACE_TCHAR *argv[])
The testLogOK and testLoginException method do exist as member functions of class A
Try this:
class A
{
public:
struct Test
{
const char *dec_text;
void (A::*TestFun)();
};
A(Test tt[])
{
for (int i=0; tt[i].dec_text; i++)
_funs[i] = tt[i];
}
void f1() { printf("this is f1\n"); }
void f2() { printf("this is f2\n"); }
void f3() { printf("this is f3\n"); }
Test _funs[100];
};
A::Test tt[] =
{
{ "Function f1", &A::f1},
{ "Function f2", &A::f2},
{ "Function f3", &A::f3},
{0, 0}
};
void test()
{
A a(tt);
(a.*(a._funs[0].TestFun))();
A *pa = new A(tt);
(pa->*(pa->_funs[1].TestFun))();
delete pa;
// EDIT: call f3
(a.*(tt[2].TestFun))(); // this will call directly from the global table
}
This will invoke the function assigned to the pointer.
This can be improved quite a bit if you typedef the pointer to the member
typedef void (A::*PF_T)();
and use a std::map as container:
std::map<std::string, PF_T> func_map;
It can be streamlined a lot more, but I hope it helps up to this point.
Firstly, I am very new to function pointers and their horrible syntax so play nice.
I am writing a method to filter all pixels in my bitmap based on a function that I pass in. I have written the method to dereference it and call it in the pixel buffer but I also need a wrapper method in my bitmap class that takes the function pointer and passes it on. How do I do it? What is the syntax? I'm a little stumped.
Here is my code with all the irrelevant bits stripped out and files combined (read all variables initialized filled etc.).
struct sColour
{
unsigned char r, g, b, a;
};
class cPixelBuffer
{
private:
sColour* _pixels;
int _width;
int _height;
int _buffersize;
public:
void FilterAll(sColour (*FilterFunc)(sColour));
};
void cPixelBuffer::FilterAll(sColour (*FilterFunc)(sColour))
{
// fast fast fast hacky FAST
for (int i = 0; i < _buffersize; i++)
{
_pixels[i] = (*FilterFunc)(_pixels[i]);
}
}
class cBitmap
{
private:
cPixelBuffer* _pixels;
public:
inline void cBitmap::Filter(sColour (*FilterFunc)(sColour))
{
//HERE!!
}
};
If I understand what you want:
inline void cBitmap::Filter(sColour (*FilterFunc)(sColour))
{
_pixels->FilterAll( FilterFunc);
}
Often dealing with function pointers can be made easier to read if you use a typedef for the function pointer type (yours actually isn't too bad on its own - they can get much worse very easily):
struct sColour
{
unsigned char r, g, b, a;
};
typedef
sColour (*FilterFunc_t)(sColour); // typedef for a FilterFunc
class cPixelBuffer
{
private:
sColour* _pixels;
int _width;
int _height;
int _buffersize;
public:
void FilterAll(FilterFunc_t FilterFunc);
};
void cPixelBuffer::FilterAll(FilterFunc_t FilterFunc)
{
// fast fast fast hacky FAST
for (int i = 0; i < _buffersize; i++)
{
_pixels[i] = (*FilterFunc)(_pixels[i]);
}
}
class cBitmap
{
private:
cPixelBuffer* _pixels;
public:
inline void cBitmap::Filter(FilterFunc_t FilterFunc)
{
_pixels->FilterAll( FilterFunc);
}
};
The Boost libraries can make your life easier here. see boost function.
For example here is a function that takes a call back function that takes two ints and returns an int:
void do_something( boost::function<int (int, int)> callback_fn );
Then it can be used like a normal function:
int result = callback_fn(1,2);
Pass it to do_something like this:
boost::function<int (int, int)> myfn = &the_actual_fn;
do_something(myfn);
With boost function you can also pass class member functions easily (see boost bind).
Good luck with your program.
You could make things clearer by using a typedef for your function pointer type:
typedef sColour (*FilterFunc_t)(sColour)
void FilterAll(FilterFunc_t FilterFunc);
Passing a variable containing a function pointer to a different function works the same as passing any other variable:
inline void cBitmap::Filter(FilterFunc_t FilterFunc) {
FilterAll(FilterFunc);
}