Here is some code:
typedef void (*ACallBack)(int i);
class SomeClass
{
private:
ACallBack aCallBack;
public:
void SetCallBack(ACallBack aCallBack);
};
void SomeClass::SetCallBack(ACallBack aCallBack)
{
this->aCallBack = aCallBack;
}
class SomeOtherClass
{
private:
SomeClass someClass;
public:
void InitializeSomeClass();
private:
void callBackMethod(int i);
};
void SomeOtherClass::InitializeSomeClass()
{
this->changeVariable = 10;
this->someClass.SetCallBack(this->callBackMethod); // DOESN'T WORK
this->someClass.UseCallBack();
}
void SomeOtherClass::callBackMethod(int i)
{
}
void globalCallBack(int i)
{
int myInt = i;
}
int main()
{
SomeClass sC;
sC.SetCallBack(globalCallBack); //WORKS!!
}
Basically if I try to set my callback function in SomeOtherClass it doesn't work but when I set it globally in main it does. What am I missing here?
Just use std::function and std::bind():
typedef std::function<void(int i)> ACallBack;
// old code pretty much the same
int main()
{
using namespace std::placeholders;
SomeClass sC;
sC.SetCallBack(globalCallBack); //WORKS!!
SomeOtherClass oC;
sC.SetCallBack(std::bind(&SomeOtherClass::callBackMethod,oC,_1)); //WORKS AS WELL!!
}
In this case you do not really need to pass void *userData but may add it as well if you need old code to compile.
You have to make the method static:
static void callBackMethod(int i, void* userData);
if you need a pointer to a method that is not static, ie an instance method, it becomes more complex.
typedef void ( myclass::*FUNC ) (int i, void* userData);
and if you want to use it, it becomes a hastlle :
myclass obj; // instantiate myclass
FUNC f = &myclass::myfunc; // assign address
( obj.*f ) ( 123, NULL ); // and call it
Related
I know this sounds like a weird thing to want, but I guess I have my reasons. I can do:
#include <string>
#include <iostream>
struct Shark
{
template <auto* static_ptr_to_self>
void whatIsMyAddress() {
std::cout << std::string("My address is ") + std::to_string((uintptr_t)static_ptr_to_self);
}
};
Shark shark;
int main()
{
shark.whatIsMyAddress<&shark>();
return 0;
}
But is there a way to achieve something like this without passing in the pointer to the function? For example can the object itself hold a pointer, resolved at compile-time, not a runtime pointer, to itself? My instinct is no because when the object is created it hasn't been declared yet. But is there some way to achieve this? If there isn't through passing the pointer as a template argument then is there a way with a constexpr member pointer?
Edit: Just to explain my question better:
struct ResourceMngr
{
void IveBeenCopied(const Handle& handle);
int referenceCountTracker[256];
};
struct Handle
{
int ID;
Handle(const Handle& other) { dynamicPtrToManager->IveBeenCopied(*this); }
ResourceMngr* dynamicPtrToManager;
};
void ResourceMngr::IveBeenCopied(const Handle& handle)
{
++referenceCountTracker[handle.ID];
}
So each handle has a pointer to let whatever is managing the resource know of 'stuff'. So now I can get rid of the pointer in handle, which has the effect of eliminating the pointer lookup (because it's constexpr) and also eliminating a pointer from each handle, by doing this:
struct ResourceMngr
{
void IveBeenCopied(const auto& handle);
int referenceCountTracker[256];
};
template <auto* static_ptr_to_manager>
struct Handle
{
int ID;
Handle() {}
Handle(const Handle& other) { static_ptr_to_manager->IveBeenCopied(*this); }
//ResourceMngr* dynamicPtrToManager; // No longer needed
};
void ResourceMngr::IveBeenCopied(const auto& handle) { ++referenceCountTracker[handle.ID]; }
ResourceMngr bufferManager;
int main()
{
Handle<&bufferManager> handle1;
Handle<&bufferManager> handle2 = handle1;
// No pointer members in each handle,
// no runtime lookup of pointers
}
And I can get a handle from a resource manager like:
template <auto* static_ptr_to_manager>
struct Handle
{
int ID;
Handle() {}
Handle(const Handle& other) {
//static_ptr_to_manager->IveBeenCopied(*this);
}
};
struct ResourceMngr
{
template <auto* static_ptr_to_self_type>
Handle<static_ptr_to_self_type> getHandleToAResourceOrObject()
{
return Handle<static_ptr_to_self_type>();
}
};
ResourceMngr bufferManager;
int main()
{
Handle<&bufferManager> handle = bufferManager.getHandleToAResourceOrObject<&bufferManager>();
// Here I have to specify in the function call
//which manager I'm referring to.
// The bufferManager couldn't use the this pointer as
//it's not constexpr and can't be used
// in template arguments
}
I have a class that I want to have a default function to be pointed to when constructing without parameters, but I want that functionality to change when a function is passed in with one of the parameters.
I'm getting the error "a value of type "int (MyClass::*)(int myVar)" cannot be assigned to an entity of type "MyClass::funcptr""
but it seems like the defaultFunction should match the definition to the function pointer.
I fought with this for a while and I'm having trouble understanding what the issue is here.
Any Help is appreciated.
--MyClass.h--
class MyClass{
private:
typedef int (*funcptr)(const int myVar);
funcptr myfuncptr;
int defaultFunc(int myVar);
public:
MyClass(funcptr functionpointer);
MyClass();
void callFunction(int myVar);
};
--MyClass.cpp--
MyClass::MyClass(){
myfuncptr = defaultFunc; //a value of type "int (MyClass::*)(int myVar)" cannot be assigned to an entity of type "MyClass::funcptr"
};
MyClass::MyClass(funcptr functionpointer){
myfuncptr = functionpointer;
};
void MyClass::callFunction(int myVar){
int i = (*myfuncptr)(myVar);
};
int MyClass::defaultFunc(int myVar){
return myVar + 3;
};
Change it into
typedef std::function<int(int)> funcptr;
(btw using is more idiomatic than typedef these days) and
myfuncptr = [this](int x){ return defaultFunc(x); };
I tried what felt like every combination of function pointer typedefs and using but in the end I think that lambda is what worked. Thanks everyone for the help.
--MyClass.h--
class MyClass{
private:
std::function<int(int)> func;
int defaultFunc(int myVar);
public:
MyClass(std::function<bool(int)> func);
MyClass();
void callFunction(int myVar);
};
--MyClass.cpp--
MyClass::MyClass(){
this->func = [=] (int a) {return defaultFunc(a);};
};
MyClass::MyClass(std::function<int(int)> func;){
this->func = func;
};
void MyClass::callFunction(int myVar){
int i = func(myVar);
};
int MyClass::defaultFunc(int myVar){
return myVar + 3;
};
I have an instance of a class A which should register a member callback in another instance of class B. I'm trying to keep the reference to the function of class A inside class B but I get a Segfault.
classA.h:
std::shared_ptr<classB> mB;
void toBeRegisteredCallback(const uint8_t val);
classA.cpp:
classA::classA(std::shared_ptr<classB> b) :
mB(std::move(b)) {
b->registerCallback(std::bind(&classB::toBeRegisteredCallback, this,
std::placeholders::_1));
}
void classB::toBeRegisteredCallback(const uint8_t val) {
LOG(INFO) << "Received a value callback!";
}
Here is the code for classB.h:
public:
void registerCallback(std::function<void(const uint8_t val)> callback);
private:
std::function<void(const uint8_t)> _callback;
Here is code for classB.cpp:
void classB::registerCallback(std::function<void(const uint8_t val)> callback) {
_callback = callback;
}
When I try to call the callback directly without assignment, it works fine:
callback(8)
However, if I try to assign it, I get a segfault at functionswap
Thanks.
Consider your classA constructor...
classA::classA(std::shared_ptr<classB> b)
: mB(std::move(b))
{
b->registerCallback(std::bind(&classB::toBeRegisteredCallback, this,
std::placeholders::_1));
}
The initialization of mB will invoke (from here(item 10))...
shared_ptr( shared_ptr&& r ) noexcept;
Move-constructs a shared_ptr from r. After the construction, *this
contains a copy of the previous state of r, r is empty and its
stored pointer is null.
Hence, in the following statement...
b->registerCallback(std::bind(&classB::toBeRegisteredCallback, this, std::placeholders::_1));
b is effectively a null pointer resulting in undefined behaviour.
I am not quite sure what you want to do, but I created a working example below.
You may give me feedback if that helps you, or if you need more explanation.
(As already mentioned by john you should be careful with the std::move command)
#include <memory>
#include <functional>
#include <iostream>
class classB
{
public:
classB() {}
~classB() {}
public:
void registerCallback(std::function<void(const uint8_t val)> callback)
{
_callback = callback;
}
void callCallback()
{
if(_callback)
_callback(8);
}
private:
std::function<void(const uint8_t)> _callback;
};
class classA
{
public:
classA(std::shared_ptr<classB> b)
: mB(b)
{
b->registerCallback(std::bind(&classA::toBeRegisteredCallback, this, std::placeholders::_1));
}
~classA(){}
void toBeRegisteredCallback(const uint8_t /*val*/)
{
std::cout << "Received a value callback!" << std::endl;
}
private:
std::shared_ptr<classB> mB;
};
int main(int, char *[])
{
std::shared_ptr<classB> b = std::make_shared<classB>();
classA localClassA = classA(b);
b->callCallback();
system("pause");
}
I want to do something like this:
struct CLI_Command{
CLI_Command(char* s, void (*h)(void)){
command_string = s;
handler = h;
}
char* command_string;
void (*handler)(void);
};
class CLI {
public:
CLI();
private:
CLI_Command cli_table[NO_CLI_COMMANDS] = {
CLI_Command("Command1", handler1),
CLI_Command("Command2", handler2)
};
void handler1(){};
void handler2(){};
};
I know that I need something similar to CLI::*handler, but I can't get the syntax right. I keep running into errors like this:
"error: no matching function for call to 'CLI_Command::CLI_Command(const char [4], <unresolved overloaded function type>)"
This illustrates the correct syntax:
class CLI;
struct CLI_Command
{
CLI_Command(char* s, void (CLI::*h)(void))
{
command_string = s;
handler = h;
}
char* command_string;
void (CLI::*handler)(void);
void raise( CLI* the_cli ) { return (the_cli->*handler)(); }
};
class CLI
{
public:
CLI();
private:
static CLI_Command cli_table[NO_CLI_COMMANDS];
void handler1(){};
void handler2(){};
};
CLI::CLI_Command cli_table[NO_CLI_COMMANDS] = {
{ "Command1", &CLI::handler1 },
{ "Command2", &CLI::handler2 }
};
Names of member functions do not decay to pointer-to-member. You must use & explicitly, and a qualified name, when creating a pointer-to-member.
In addition to other answers, another option is to use std::function together with std::bind():
struct CLI_Command{
...
std::function<void> handler;
};
class CLI {
...
CLI_Command cli_table[NO_CLI_COMMANDS] = {
{ "Command1", std::bind(&CLI::handler1, this) },
{ "Command2", std::bind(&CLI::handler2, this) }
};
void handler1(){};
void handler2(){};
};
void handler1(){}
void handler2(){}
are member functions of CLI. The correct way to "address to" them is &CLI::handler1 and not handler1. However then, they won't be accepted by void (*h)(void), which would need to be changed to void (CLI::*h)(void). But that is probably not what you want.
Maybe consider reading about std::function for type erasure, or make your handler1/handler2 static.
You should use the syntax for a pointer to class member instead of the syntax for a loose function pointer.
class CLI;
struct CLI_Command{
CLI_Command(char* s, void (CLI::*h)(void)){
command_string = s;
handler = h;
}
char* command_string;
void (CLI::*handler)(void);
};
In addition, make sure you call the function through the pointer of the current CLI class;
void CLI::process(char *cmd) {
CLI_Command command* = /* lookup the command */
this->(command->handle)();
}
To get it working, make your methods static
static void handler1(){};
static void handler2(){};
Whatever consequences (read here please, for more detailed info) this will have :-( .
Consider the following code:
struct data
{
int foo;
int bar;
};
data a;
a.foo = 200;
a.bar = 300;
static void update(data* a, int rspec)
{
if (!rspec) //my data management
{
3rdPartyApi->CreateStream();
3rdPartyApi->PushData(a->foo);
3rdPartyApi->PushData(a->bar);
3rdPartyApi->CloseStream();
}
else // internal data management
{
3rdPartyApi->CreateStream();
3rdPartyApi->PushData(3rdPartyApi->BufferQueue);
3rdPartyApi->CloseStream();
}
3rdPartyApi->PushStream(3rdPartyApi->GetLastStreamBuffer().POD());
}
Lets say I change the value of a.foo or a.bar, and it requires me to call Update there-after the assignment. Can this be done, without actually calling Update() on each change manually?
[EDIT]
Note that the update function created is also assigned to a function pointer for
the third party API, so it can do it's own internal updating. So making the update function non-global is impossible, and thus is why the current update function is global.
[EDIT]
I also rewrote my example to be more understanding and correct to the actual API I'm using
e.g
3rdPartyApi->StreamUpdate((void (*)(void*, int))update);
Yes, you can. Use class methods for this. Pass a static method from your class to the 3rd party API as an update function.
class data
{
public:
void set_foo(int new_foo);
void set_bar(int new_bar);
int get_foo() const;
int get_bar() const;
// This is the update signature which the 3rd party API can accept.
static void update(void* ptr, int rspec);
private:
// These are private so we can control their access.
int foo;
int bar;
};
void data::set_foo(int new_foo)
{
foo = new_foo;
// 'this' is a special pointer for current data object.
update(this);
}
void data::set_bar(int new_bar)
{
bar = new_bar;
update(this);
}
int data::get_foo() const
{
return foo;
}
int data::get_bar() const
{
return bar;
}
// This is needed if the 3rd party API can only call C bindings.
// If it's a C++ API this is not needed.
extern "C" {
void data::update(void* ptr, int rspec)
{
if (!rspec) //my data management
{
// You have to cast to data* from void*.
data* data_ptr = reinterpret_cast<data*>(ptr);
3rdPartyApi->CreateStream();
3rdPartyApi->PushData(data_ptr->foo);
3rdPartyApi->PushData(data_ptr->bar);
3rdPartyApi->CloseStream();
}
else // internal data management
{
3rdPartyApi->CreateStream();
3rdPartyApi->PushData(3rdPartyApi->BufferQueue);
3rdPartyApi->CloseStream();
}
3rdPartyApi->PushStream(3rdPartyApi->GetLastStreamBuffer().POD());
}
} /* extern "C" */
Then:
3rdPartyApi->StreamUpdate(&data::update);
data a;
a.set_foo(200);
a.set_bar(300);
Note that use of a struct instead of a class is equally fine here. But the convention is to use classes in C++. There is only a minor difference which you can learn later.
It is hard to write code for foo, bar, and data, so let's make it more concrete:
class point
{
public:
int x_coord() const;
int y_coord() const;
void move_to(int new_x, int new_y);
private:
void update_3rd_party();
int x;
int y;
};
void point::move_to(int new_x, int new_y)
{
x = new_x;
y = new_y;
// whatever else needs to be done
update_3rd_party();
}
You need to make use of Observer design pattern or a slight variant of it.
See this example here.
The usual way would be to turn foo and bar into some type that overloads the assignment operator:
class updated_int {
int value;
public:
updated_int(int init = 0) : value(init) {}
updated_int &operator=(int new_val) {
value = new_val;
update();
return *this;
}
// You might want to declare this private and not implement it.
updated_int &operator=(updated_int const &r) {
value = r.value;
update();
return *this;
}
operator int() { return value; }
};
struct data {
updated_int foo;
updated_int bar;
}
data a;
a.foo = 1; // operator= will call update() automatically.