I wrote a special class which checks some states of some external stuff and if something changes I would like to call a callback function.
These function should be not only a global function instead of a function of a special class.
To show what I mean here is some code:
void myClass::addCallbackFunction(unsigned int key, TheSpecialClass* obj, void (TheSpecialClass::*func)(unsigned int, bool)) {
if(!obj) {
return;
}
callbackFunction cbf;
cbf.object = obj;
cbf.func = func;
if(!(callbackFunctions.find(key) == callbackFunctions.end())) {
//Key allready exists.
callbackFunctions[key].push_back(cbf);
} else {
//Key does not exists at the moment. Just create it.
vector<callbackFunction> v;
v.push_back(cbf);
callbackFunctions.insert({key, v});
}
}
void MyClass::callCallbackFunction(unsigned int key, bool newValue) {
vector<callbackFunction> cbfs;
//hasKey..
if(!(callbackFunctions.find(key) == callbackFunctions.end())) {
cbfs = callbackFunctions[key];
}
//calling every function which should be called on a state change.
for(vector<callbackFunction>::iterator it = cbfs.begin(); it != cbfs.end(); ++it) {
((it->object)->*(it->func))(key, newValue);
}
}
//to show the struct and the used map
struct callbackFunction {
TheSpecialClass* object;
void (TheSpecialClass::*func)(unsigned int, bool) ;
};
map<unsigned int, vector<callbackFunction> > callbackFunctions;
Now I want to make 'TheSpecialClass' to some kind of Pointer to a class which can variate. I found void-Pointer but then I have to know which class I passed. I thought there is something like the function pointer out there which I did not found yet.
Do someone know a solution?
I used boost::signal2 to match my usecase.
A tutorial for boost::signal2 is found here.
The signals whould only call functions. Not functions on a special object. There is a workaround by using boost::bind() like:
boost::bind(boost::mem_fn(&SpecialClass::memberFunctionOfTheClass), PointerToTheObjectOfSepcialClass, _1)
The _1 is a placeholder which creates a function (reference) which requires one argument. You can add some more placeholders to use more arguments.
Related
I have a class "Person" like so:
typedef void (*action)();
typedef std::unordered_map<int, action> keybindMap; // maps keycodes to functions
class Person {
keybindMap keybinds;
void doSomething();
}
I use this to call the functions at the right times:
iter = keybinds.find(event.key.keysym.sym); // event.key.keysym.sym is the key code
if (iter != keybinds.end())
{
(*iter->second)(); // call whatever function that key is bound to.
}
To bind a key, I used keybinds.insert_or_assign(SDLK_a, doSomething). However, this doesn't work (because doSomething is non-static). How do I change the binding code and/or the (*iter->second)() part so that I can call something equivalent to person.doSomething?
A non-static method requires an object to call it on. An ordinary function pointer doesn't have room to hold a reference to an object.
If you change your map to hold std::function instead, you can then use std::bind() or a lambda to associate an object with a method pointer, eg:
using action = std::function<void()>;
using keybindMap = std::unordered_map<int, action>;
class Person {
keybindMap keybinds;
void doSomething();
};
...
Person p, otherP; //must outlive the map...
p.keybinds[...] = [&otherP](){ otherP.doSomething(); }
...
iter = keybinds.find(event.key.keysym.sym);
if (iter != keybinds.end()) {
iter->second();
}
On the other hand, if all of the target methods are in the same class/object, you can use a plain method pointer instead of std::function, which will reduce some overhead, eg:
class Person {
using action = void (Person::*)();
using keybindMap = std::unordered_map<int, action>;
keybindMap keybinds;
void doSomething();
};
...
keybinds[...] = &Person::doSomething;
...
iter = keybinds.find(event.key.keysym.sym);
if (iter != keybinds.end()) {
(this->*(iter->second))();
}
I am trying to do set a void function in c++ inside another void. I was instructed to use this non-functioning code:
void function() {
log("Original function")
}
int main(){
function = []()
{
log("New Function");
};
}
and get this :
error: invalid use of member function ‘void function()’ (did you forget the ‘()’ ?).
Can anyone help? Is this even possible and if not then can anyone provide an alternative? All help is approved.
I think you want function to be a function pointer, not a function.
So maybe something a little like this:
void (*function)();
int main(){
function = []()
{
log("New Function");
};
return 0;
}
Function definitions cannot be changed at runtime like this, so you will need to use some sort rebindable object that is invocable instead.
If your lambda is never going to capture a value, then you can use function pointers for this purpose -- since a non-capturing lambda can be converted to a function pointer. For example:
using function_t = void(*)();
void function_default() {
log("Original function");
}
function_t function = &function_default;
int main() {
function = []{
log("New Function");
};
}
Try it Online
However, be aware that as soon as you want to capture data in that lambda, this will not work. At which point you'll be better off using something like std::function which can work with any invocable object:
using function_t = std::function<void()>;
void function_default() {
log("Original function");
}
function_t function = &function_default;
int main() {
int some_value = 5;
function = [=]{
log("New Function with value = " + std::to_string(some_value));
};
}
Try it Online
To answer your question, yes, you can do this, but it will require the usage of a lambda function:
void main()
{
auto func = []()-> void // Note: This is a lambda function.
{
// Code...
};
// If you want to run "func" call it in your void, if not, leave it uncalled.
func();
}
For more information on lambdas, I'll provide a link here.
I'm writing a simple event bus system to get familiar with this model. I have an addEvent function which takes an event name (string) and a function. I'm having trouble establishing my event class.
// Event class to define our event
class Event
{
public:
// function is some function that needs to be executed later
Event(const string eventName, void * function)
{
msgEvent.first = event;
msgEvent.second = function;
}
string getEvent(){
return msgEvent;
}
private:
pair<string, void*> msgEvent;
};
so when I make a call addEvent("open", openFunction), I would like to store this information as part of an Event.
I'm having a hard time understanding how I can store the function and if I'm correctly passing a function in the constructor as a parameter.
You can use function pointers or std::function. void* is for sure not correct. In any case, you need to know what signature your function has. Let's say, your functions do not take any input and do not return. Then, their signature is void()
Then, you can use the following code:
#include<functional>
#include<string>
class Event
{
public:
// function is some function that needs to be executed later
Event(const std::string eventName, std::function<void()> functionName)
{
msgEvent.first = eventName;
msgEvent.second = functionName;
}
std::string getEvent(){
return msgEvent.first;
}
void execute() {
msgEvent.second();
}
private:
std::pair< std::string, std::function<void()> > msgEvent; // why are you using
// std::pair here?
};
Now, you can write
Event myEvent( "open", [](){ /* do something */ } );
myEvent.execute();
I am getting the error term does not evaluate to a function taking 1 arguments when trying to call a function pointer.
The function pointer is stored in a struct. The struct is then stored in a map.
Definition:
typedef void (CLIOptions::*OptionHandler)(QString);
struct OptionDefinition {
QString name;
QString description;
QString type;
OptionHandler handler;
};
typedef std::map<QString, OptionDefinition> CLIOptionMap;
I initialise the map like this:
CLIOptionMap optionMap =
{
{
QString("set-tcp-host"),
{
QString("set-tcph"),
QString("Set the TCP server host address"),
QString("string"),
&CLIOptions::setTcpHost
}
},
// etc...
}
The problem occurs when I try to iterate through the map and call the handler:
for (it = optionMap.begin(); it != optionMap.end(); ++it) {
QString value = /*snip...*/
(it->second.handler)(value)
}
What is my problem here?
Your problem is that you don't have a function pointer, you have a pointer to member function, and they are very different beasts. A pointer-to-member-function isn't even a pointer in general (it has to be able to handle pointer to a virtual function in a second virtual base class!)
Given you have a pmf, you need an object to invoke the pmf on. So something like:
for (it = optionMap.begin(); it != optionMap.end(); ++it) {
QString value = /*snip...*/
const auto pmf = it->second.handler;
(mOptionHandler.*pmf)(value);
}
actually, if you going to use C++11 auto, you can also use the foreach loop:
for (const auto& option : optionMap) {
const auto pmf = option.handler;
(mOptionHandler.*pmf)(option.value);
}
I have a vector populated with callback functions and I would like to check whether callback to the function already exists prior to adding it. I don't know whether it will even work bu so far it doesn't even compile.
vector<std::function<void(void*)>> _callbacks;
void Event::RegisterCallback(std::function<void(void*)> callback)
{
if (callback == NULL)
return;
vector<std::function<void(void*)>>::iterator it = std::find(_callbacks.begin(), _callbacks.end(), callback);
if (it == _callbacks.end())
{
_callbacks.push_back(callback);
}
else
{
//print error
throw;
}
}
This gives a compile error:
"Overload resolution selected deleted operator '=='" in alorithm(805). This is related to the find function call.
How do I get this to work and is it even going to compare function calls to the same method properly?
Thanks
As noted in the comments the simplest solution is to use default C-style function pointers as they support == operator in opposite to C++11 function which does not.
using func_type = void(*)();
vector<func_type> _callbacks;
void Event::RegisterCallback(func_type callback)
{
if (callback == nullptr)
return;
auto it = std::find(_callbacks.begin(), _callbacks.end(), callback);
if (it == _callbacks.end()) {
_callbacks.push_back(callback);
}
else {
throw;
}
}
void f() {};
void g() {};
/*
evt.RegisterCallback(f); // works fine
evt.RegisterCallback(g); // works fine
evt.RegisterCallback(f); // throws exception
*/
If you don't like this approach you can write your own function-pointer class with support of equality operator.
Another solution is to have a class with a std::function member and another comperable member, and then overloading the () to get the std::function parameter and call it with the parameter, and the == operator to compeare the class using the comperable member.
CompareableFunction.h:
class CompareableFunction
{
public:
CompareableFunction(int nId, std::function<void(parameter)> handler);
~CompareableFunction();
void operator()(parameter param);
bool operator== (CompareableFunction compareableFunc);
private:
std::function<void(parameter)> m_handler;
int m_nId;
};
CompareableFunction.cpp:
CompareableFunction::CompareableFunction(int nId, std::function<void(parameter)> handler)
{
m_nId = nId;
m_handler = handler;
}
CompareableFunction::~CompareableFunction()
{
}
void CompareableFunction::operator()(parameter param)
{
return m_handler(param);
}
bool CompareableFunction::operator==(CompareableFunction compareableFunc)
{
return (m_nId == compareableFunc.m_nId);
}
EDIT: you can convert the std::function to a C-style function pointer and use it to compare. example to a conversion is here: http://www.cplusplus.com/forum/general/63552/