c++ callbacks to another member function - c++

I have a question on callbacks. Previously, I am associating my callbacks to a class Q
class Q{
using Callback = std::function<void(char*, int)>;
Q:Q();
Q:~Q();
void Q::RegisterCB(Callback callbackfunc)
{
callback_func = callbackfunc;
}
void Q:someEvent()
{
callback_func();
}
};
void handleCallback( char*, int)
{
// perform some routine
}
// from my main file
int main()
{
Q q;
q.RegisterCB(&handleCallback);
}
It works well for me. However, when I need to transfer the handleCallback function to another class for cleaner code. I have problem with using same code
class R{
void R::handleCallback( char*, int)
{
// perform some routine
}
void R::someOp()
{
// q is some member variables of R
q.RegisterCB(&R::handleCallback, this);
}
};
However, i run into some problems of saying there is a "no matching function for call to .....". I thought it was just simply assigning from function name to class function name
May I have a hint to where I might go wrong?
Regards

&R::handleCallback has the type void (R::*)(char*, int), which is not convertible to std::function<void(char*, int)>.
Also, RegisterCB takes one argument, not two.
The most straightforward fix is to wrap the call in a lambda function,
q.RegisterCB([this](char* p, int x) { handleCallback(p, x); });

Example on how to use a lambda function to register a member function of an instance of R as event handler. (I replaced char* with string_view out of habit, it's not essential for this example). The use of "const" wherever you can is a recommendation.
#include <functional>
#include <string_view>
#include <iostream>
class Q
{
public:
// use const arguments, the callback is not supposed to change them
// just passing information on to callback
using callback_t = std::function<void(const std::string_view&, const int)>;
// initialize callback with a (lambda) function that does nothing
// this prevents the need for a check if callback has been set or not
// (Pattern : Null Strategy)
Q() :
m_callback_func( [](const std::string_view&,const int) {} )
{
}
~Q() = default;
void RegisterCallback(callback_t fn)
{
m_callback_func = fn;
}
void Event(const std::string_view& string, const int value)
{
m_callback_func(string,value);
}
private:
callback_t m_callback_func;
};
void handleCallback(const std::string_view& string, const int value)
{
std::cout << string << ", " << value << "\n";
}
class R
{
public:
void handleCallback(const std::string_view& string, const int value)
{
std::cout << string << ", " << value << "\n";
}
};
// from my main file
int main()
{
Q q1;
q1.RegisterCallback(handleCallback);
q1.Event("Hello", 42);
// to pass a callback to an instance of a class
// you can use a lambda function https://en.cppreference.com/w/cpp/language/lambda
R r;
Q q2;
q2.RegisterCallback([&r](const std::string_view& string, const int value)
{
r.handleCallback(string,value);
});
q2.Event("World",21);
return 0;
}

Related

Passing a member function of another class into a std::function parameter

I have a class with a function that takes a std::function and stores it. This part seems to compile ok (but please point out any issue if there are any)
#include <functional>
#include <iostream>
struct worker
{
std::function<bool(std::string)> m_callback;
void do_work(std::function<bool(std::string)> callback)
{
m_callback = std::bind(callback, std::placeholders::_1);
callback("hello world\n");
}
};
// pretty boring class - a cut down of my actual class
struct helper
{
worker the_worker;
bool work_callback(std::string str)
{
std::cout << str << std::endl;
return true;
}
};
int main()
{
helper the_helper;
//the_helper.the_worker.do_work(std::bind(&helper::work_callback, the_helper, std::placeholders::_1)); // <---- SEGFAULT (but works in minimal example)
the_helper.the_worker.do_work(std::bind(&helper::work_callback, &the_helper, std::placeholders::_1)); // <---- SEEMS TO WORK
}
I get a segfault, but I am not sure why. I have used this before, in fact, I copied this example from another place I used it. The only real difference that the member function was part of the class I called it from (i.e. this instead of the_helper).
So this is why I am also asking if there is anything else I am doing wrong in general? Like should I be passing the std::function as:
void do_work(std::function<bool(std::string)>&& callback)
or
void do_work(std::function<bool(std::string)>& callback)
As also noted by #Rakete1111 in comments, the problem probably was in this code:
bool work_callback(std::string str)
{
std::cout << str << std::endl;
}
In C++ if a non-void function does not return a value the result is undefined behavior.
This example will crash with clang but pass with gcc.
If helper::work_callback returns (e.g, true) the code works just fine.
I don't know why your code seg faults because I was spoiled and skipped std::bind straight to lambdas. Since you use C++11 you should really convert your code from std::bind to lambdas:
struct worker
{
std::function<bool(std::string)> m_callback;
void do_work(std::function<bool(std::string)> callback)
{
m_callback = callback;
callback("hello world\n");
}
};
Now with work_callback and calling do_work things need some analysis.
First version:
struct helper
{
worker the_worker;
bool work_callback(std::string)
{
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work([&](std::string s) { return the_helper.work_callback(s); });
}
Now this version works with your toy example. However out in the wild you need to be careful. The lambda passed to do_work and then stored in the_worker captures the_helper by reference. This means that this code is valid only if the helper object passed as reference to the lambda outlives the worker object that stores the m_callback. In your example the worker object is a sub-object of the the helper class so this is true. However if in your real example this is not the case or you cannot prove this, then you need to capture by value.
First attempt to capture by value (does not compile):
struct helper
{
worker the_worker;
bool work_callback(std::string)
{
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work([=](std::string s) { return the_helper.work_callback(s); });
}
This does not compile because the copy of the_helper stored in the lambda object is const by default and as such you cannot call work_callback on it.
A questionable solution if you can't make work_callback const is to make the lambda mutable:
struct helper
{
worker the_worker;
bool work_callback(std::string)
{
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work([=](std::string s) mutable { return the_helper.work_callback(s); });
}
But you need to think if this is what you intended.
What would make more sense is to make work_callback const:
struct helper
{
worker the_worker;
bool work_callback(std::string) const
{
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work([=](std::string s) { return the_helper.work_callback(s); });
}
The reason for getting SEGFAULT has been already mentioned in the comments.
However, I would like to point out that, you need to use neither std::bind nor std::function, here in your given case. Instead, simply having a lambda and a function pointer you can handle what you intend to do.
struct worker
{
typedef bool(*fPtr)(const std::string&); // define fun ptr type
fPtr m_callback;
void do_work(const std::string& str)
{
// define a lambda
m_callback = [](const std::string& str)
{
/* do something with string*/
std::cout << "Call from worker: " << str << "\n";
return true;
};
bool flag = m_callback(str);// just call the lambda here
/* do some other stuff*/
}
};
struct helper
{
worker the_worker;
bool work_callback(const std::string& str)
{
std::cout << "Call from helper: ";
this->the_worker.do_work(str);
return true; ------------------------>// remmeber to keep the promise
}
};
And use case would be:
int main()
{
helper the_helper;
the_helper.work_callback(std::string("hello world"));
// or if you intend to use
the_helper.the_worker.do_work(std::string("hello world"));
return 0;
}
see Output here:
PS: In the above case, if worker does not required m_callback for later cases(i.e, only for do_work()), then you can remove this member, as lambdas can be created and called at same place where it has been declared.
struct worker
{
void do_work(const std::string& str)
{
bool flag = [](const std::string& str)->bool
{
/* do something with string*/
std::cout << "Call from worker: " << str << "\n";
return true;
}(str); -------------------------------------> // function call
/* do other stuff */
}
};

Handle non-member function pointer and member function pointer at the same time

I want to do a member function that will call every X seconds. I did a little prototype that can handle non member function, but I don't know if I did it well, and I can't handle both member function and non member function.
I have an Event object, which handle the function and the delay, with a basic timer, to detect when we need to run the function:
typedef void (*ScheduleFunction)(float dt);
class Event
{
private:
ScheduleFunction m_Func;
double m_Timer;
double m_Delay;
public:
Event(ScheduleFunction function, double delay)
{
m_Func = function;
m_Delay = delay;
}
void Call(float dt)
{
m_Timer += dt;
if (m_Timer >= m_Delay)
{
m_Func(dt);
m_Timer = 0.0;
}
}
};
Then, I have another object that call every frames each function into a vector<Event>:
class Handler
{
private:
void m_MemberFunction(float dt)
{
std::cout << "A member function." << std::endl;
}
std::vector<Event> m_ScheduleItems;
public:
Handler()
{
// This will not compile, because the function expect a non member function
Schedule(&Handler::m_MemberFunction, 1.0);
}
void CallScheduledFunctions(float dt)
{
for (std::vector<Event>::iterator it = m_ScheduleItems.begin(); it != m_ScheduleItems.end(); ++it)
{
it->Call(dt);
}
}
void Schedule(ScheduleFunction func, double delay)
{
Event event(func, delay);
m_ScheduleItems.push_back(event);
}
void Unschedule()
{
// TODO
}
};
As you can see, I have a function Schedule that register new Event. But right now, it only handle non member function. Is there a way that I can handle non member function and member function, not only from the Handler but also on all others objects?
If there is no way, how can I achieve this?
Using std::function is the way to go. Anything that can be called can be transformed/wrapped into an std::function.
In your case, you could write your Event constructor like this:
Event(std::function<void(float)>, double delay);
And you can call this with a standalone function, a functor or a lambda.
Some examples:
// declaration
auto myDummyFunction (float) -> void;
// Calling the constructor
auto event = Event(myDummyFunction,1.0);
If we want to pass a member function, just use a lambda:
// declaration of the class with the member function
class SomeOtherClass
{
public:
auto someMethod(float) -> void;
};
// Calling the constructor
auto someOtherClass = SomeOtherClass{};
auto event = Event([&someOtherClass](float f){someOtherClass.someMethod(v)},1.0);
In general I find lambda's more readable and flexible than the std::bind approach. As far as I can remember, it's advised (was it Herb or Scott?) not to use std::bind anymore, but to use lambda's instead.
UPDATE 1
Added "call any object's members" below.
BRIEF
I recommend using std::function and std::bind. But remind that std::function has some overhead due to the internal mechanisms!
std::function is very powerful as there are many things you can store in it.
Important:
Using a function-pointer only approach is possible, but would cause some code and complexity if you must retain the simple unified interface.
EXAMPLE
#include <functional>
using ScheduleFunction_t = std::function<void(float)>;
class Event {
private:
ScheduleFunction_t
m_Func;
double
m_Timer,
m_Delay;
public:
Event(
ScheduleFunction_t const&function,
double delay)
: m_Func(function)
, m_Delay(delay)
{ }
void Call(float dt) {
m_Timer += dt;
if (m_Timer >= m_Delay)
{
// Important, if you do not assert in the constructor, check if the fn is valid...
// The ctr shouldn't throw on runtime assert fail... memory leak and incpomplete construction...
if(m_Func)
m_Func(dt);
m_Timer = 0.0;
}
}
};
As you can see, including the <functional> header will give you the template std::function<R(Args...)>, where R is the return type and Args... a comma separated list of fully qualified argument types.
void g_freeFunction(float f) {
std::cout << "Globally floating for " << f << "ms" << std::endl;
}
class Handler {
private:
void m_MemberFunction(float dt) {
std::cout << "Floating around with " << dt << " m/s" << std::endl;
}
std::vector<Event> m_ScheduleItems;
public:
Handler() {
// Bind member function
Schedule<Handler, &Handler::m_MemberFunction>(this);
// Or free
Schedule(&g_freeFunction);
// Or lambda
Schedule([](float f) -> void { std::cout << "Weeeeeeeh...." << std::endl; });
}
void CallScheduledFunctions(float dt)
{
for(Event& e : m_ScheduleItems)
e.Call(dt);
}
template <typename TClass, void(TClass::*TFunc)(float)>
void Schedule(
TClass *const pInstance,
double delay = 0.0)
{
m_ScheduleItems.emplace_back(std::bind(TFunc, pInstance, std::placeholders::_1), delay); // Create in place at the end of vector.
}
void Schedule(
ScheduleFunction_t fn,
double delay = 0.0)
{
m_ScheduleItems.emplace_back(fn, delay); // Create in place at the end of vector.
}
void Unschedule() { /* TODO */ }
};
This way you can now bind almost whatever you want. :D
Update:
The Schedule-function can not be called for any other type that has a matching public method, e.g.:
struct Test {
void foo(float f) {
std::cout << "TEST ME!" << std::endl;
}
};
int main()
{
Test t={};
Handler h = Handler();
h.Schedule<Test, &Test::foo>(&t);
for(uint32_t k=0; k < 32; ++k)
h.CallScheduledFunctions(k);
}
RESOURCES
http://en.cppreference.com/w/cpp/utility/functional
http://en.cppreference.com/w/cpp/utility/functional/function
http://en.cppreference.com/w/cpp/utility/functional/bind
WORKING EXAMPLE
http://cpp.sh/7uluut

pass userData from callback-begin to callback-end

How to appropriately cache userData that is generated from user's callbackBegin() and send it to user's callbackEnd().
Simple version (No userData - demo)
I want to create a complex database that support callback. For MCVE, let's say it is MyArray.
Here is a simple array class that supports callback but no userData.
#include <iostream>
template<class Derived>class MyArray{ //library - I design it.
public: void push_back(int s){
static_cast<Derived*>(this)->callbackBegin(s);
//do something about array
static_cast<Derived*>(this)->callbackEnd(s);
}
//other fields / functions
};
class Callback : public MyArray<Callback>{ //user's class
public: void callbackBegin(int s){
std::cout<<"callbackBegin"<<std::endl;
}
public: void callbackEnd(int s){
std::cout<<"callbackEnd"<<std::endl;
}
};
int main() {
Callback c;
c.push_back(5); //print: callbackBegin callbackEnd
return 0;
}
It works correctly.
The next step : I want to pass some userData from Callback::callbackBegin() to Callback::callbackEnd().
For example, userData is a clock time when Callback::callbackBegin() is called.
My poor solution (void*& userdata : demo)
Here is my attempt to implement it :-
#include <iostream>
#include <time.h>
template<class Derived>class MyArray{
public: void push_back(int s){
void* userData=nullptr; //#
static_cast<Derived*>(this)->callbackBegin(s,userData); //# ugly
//do something about array
static_cast<Derived*>(this)->callbackEnd(s,userData); //# ugly
}
};
class Callback : public MyArray<Callback>{
public: void callbackBegin(int s,void*& userData){ //#
userData=new clock_t(clock()); //# danger
std::cout<<"callbackBegin"<<std::endl;
}
public: void callbackEnd(int s,void*& userData){ //#
clock_t* userDataTyped=static_cast<clock_t*>(userData);
clock_t clock2=clock();
clock_t different=clock2 - (*userDataTyped);
std::cout<<"callbackEnd time(second)="
<<((float)different)/CLOCKS_PER_SEC<<std::endl;
delete userDataTyped; //# danger
}
};
int main() {
Callback c;
c.push_back(5); //print: callbackBegin callbackEnd time(second)=8.5e-05
return 0;
}
It also works correctly, but I believe it is a bad design (at various #) :-
new/delete in 2 places : potential memory leaking.
Strong pointer is preferred, but I don't know how to.
static_cast<clock_t*>(userData) is code-smell, at least for me.
(minor issue) an extra ugly parameter void*&
Question: What are design patterns / C++ magic to avoid such issues, while make MyArray concise, easy to use, maintainable (i.e. not much worse than the Simple version)?
Other notes:
In real cases, <5% of user's callback classes need userData.
Thus, I feel very reluctant to add void&* as an extra parameter.
Clarify: (edited) The minority cases usually need different types of userData e.g. Callback1 need clock_t, Callback2 need std::string, etc.
Proposed solution should restrain from using std::function<> or virtual function, because the performance is a major concern here.
Thank.
Pass data through a void pointer is a good C solution but (IMHO) not a C++ (specially: not a C++11/c++14/C++17, with auto and std::tuple) good one.
So I suggest to return a value from callbackBegin() and pass the value as first argument to `callbackEnd(); something like
auto r = static_cast<Derived*>(this)->callbackBegin(s);
static_cast<Derived*>(this)->callbackEnd(r, s);
Observe (C++11 and newer magic) that using auto as type of the value returned by callbackBegin(), you can return different types from different `callbackBegin().
Bonus suggestion: be more generic in MyArray::push_back(): using variadic templates, there is no need of fix the number and the types of arguments received by callbackBack() and callbackEnd().
Using variadic templates you can modify push_back() as follows
template <typename ... Args>
void push_back (Args const & ... args)
{
auto r = static_cast<Derived*>(this)->callbackBegin(args...);
static_cast<Derived*>(this)->callbackEnd(r, args...);
}
The following is a full working example with two different callback classes (with different number of arguments and different return types)
#include <tuple>
#include <iostream>
template <typename derT>
struct myA
{
template <typename ... Args>
void push_back (Args const & ... args)
{
auto r = static_cast<derT*>(this)->callbackBegin(args...);
static_cast<derT*>(this)->callbackEnd(r, args...);
}
};
struct cb1 : public myA<cb1>
{
int callbackBegin (int s)
{ std::cout << "cb1 b" << std::endl; return s+5; }
void callbackEnd (int r, int s)
{ std::cout << "cb1 e -" << r << ", " << s << std::endl; }
};
struct cb2 : public myA<cb2>
{
std::tuple<std::string, int> callbackBegin (std::string const & name,
int num)
{ std::cout << "cb2 b" << std::endl; return {name+";", num+1}; }
void callbackEnd (std::tuple<std::string, int> const &,
std::string const & name, int num)
{ std::cout << "cb2 e -" << name << ", " << num << std::endl; }
};
int main ()
{
cb1 c1;
c1.push_back(5);
cb2 c2;
c2.push_back("string arg", 7);
return 0;
}
std::any would allow you to hold clock_t (or any other) object and do away with the void* pointers, however that's a C++17 concept and not yet widely available (although there are implementations such as boost::any).
In the meantime, your code may benefit from a little composition over inheritance, as array and callback are conceptually pretty different and don't seem to belong in the same inheritance hierarchy. So, preferring composition, the code might look something like:
template<class T> struct ICallback
{
virtual void callbackBegin(int s, std::unique_ptr<T>& p) = 0;
virtual void callbackEnd(int s, std::unique_ptr<T>& p) = 0;
};
template<class T> class MyArray
{
public:
MyArray(std::shared_ptr<ICallback<T>> cb) { callback = cb; }
void push_back(int s)
{
callback->callbackBegin(s, usrDataPtr);
//do something about array
callback->callbackEnd(s, usrDataPtr);
}
protected:
std::shared_ptr<ICallback<T>> callback;
std::unique_ptr<T> usrDataPtr;
};
class ClockCallback : public ICallback<clock_t>
{
public:
void callbackBegin(int s, std::unique_ptr<clock_t>& c){
c = std::make_unique<clock_t>(clock());
std::cout << "callbackBegin" << std::endl;
}
void callbackEnd(int s, std::unique_ptr<clock_t>& c){
clock_t clock2 = clock();
clock_t different = clock2 - (*c);
std::cout << "callbackEnd time(second)="
<< ((float)different) / CLOCKS_PER_SEC << std::endl;
}
};
int main() {
std::shared_ptr<ClockCallback> c = std::make_shared<ClockCallback>();
MyArray<clock_t> ma(c);
ma.push_back(7);
return 0;
}
You can use a smart pointer to avoid manually deleting your userData
std::unique_ptr<clock_t> userData;
pass it as a reference to your callbacks
void callbackBegin(int s, std::unique_ptr<clock_t> &userData)
and initialize it this way
userData = std::make_unique<clock_t>(clock())
The C++ magic you're asking about is a known as a virtual method. Virtual method is one of the C++ native ways to implement the callback:
class MyArray{
public:
void push_back(int s) {
const auto userData = callbackBegin(s); //# beautiful
//do something about array
callbackEnd(s, userData); //# beautiful
}
private:
virtual clock_t callbackBegin(int) const = 0;
virtual void callbackEnd(int, const clock_t&) const = 0;
};
class Callback : public MyArray{
clock_t callbackBegin(int s) const final {
std::cout<<"callbackBegin"<<std::endl;
return clock(); //# safe
}
void callbackEnd(int s,const clock_t& userData) const final { //#
const auto different = clock() - userDataTyped;
std::cout << "callbackEnd time(second)=";
std::cout << different/CLOCKS_PER_SEC << std::endl;
//# safe
}
};
Another way is to pass two callable objects to the MyArray ctor and using those objects in the push_back method. The callable objects shall store calls to the relevant class Callback methods. Use std::function to implement those callable objects.

How to work around C++ pointer-to-member function limitation

C++ has limited ability to use pointer-to-member functions. I need something that will allow me to dynamically choose a callback member function, in order to use the Visitor pattern of the XMLNode::Accept(XMLVisitor *visitor) method from the TinyXML2 library.
To use XMLNode::Accept(), I must call it with a class which implements the XMLVisitor interface. Hence:
typedef bool (*Callback)(string, string);
class MyVisitor : public tinyxml2::XMLVisitor {
public:
bool VisitExit(const tinyxml2::XMLElement &e) {
callback(e.Name(), e.GetText());
}
Callback callback;
}
This works fine if my caller is NOT an object which wants to use one of its own methods as a callback function (so that it can access class variables). For example, this works:
bool myCallBackFunc(string e, string v) {
cout << "Element " << e << " has value " << v << endl;
return true;
}
int main(...) {
tinyxml2::XMLDocument doc;
doc.LoadFile("somefile.xml");
MyVisitor visit;
visit.callback = myCallBackFunc;
doc.Accept(&visit);
}
However, in my use case, the parsing is done inside a method in a class. I have multiple applications which have similar but unique such classes. I'd like to use only one generic MyVisitor class, rather than have the visitor class have unique knowledge of the internals of each class which will call it.
Thus, it would be convenient if the callback function were a method in each calling class so that I can affect the internal state of the object instantiated from that calling class.
Top level: I have 5 server applications which talk to 5 different trading partners, who all send XML responses, but each is enough different that each server app has a class which is unique to that trading partner. I'm trying to follow good OO and DRY design, and avoid extra classes having unique knowledge while still doing basically the same work.
Here's the class method I want Accept() to call back.
ServiceClass::changeState(string elem, string value) {
// Logic which sets member vars based on element found and its value.
}
Here's the class method which will call Accept() to walk the XML:
ServiceClass::processResponse(string xml) {
// Parse XML and do something only if certain elements present.
tinyxml2::XMLDocument doc;
doc.Parse(xml.c_str(), xml.length());
MyVisitor visit;
visit.callback = &changeState; // ERROR. Does not work.
visit.callback = &ServiceClass::changeState; // ERROR. Does not work.
doc.Accept(&visit);
}
What's a simple way to get what I want? I can imagine more classes with derived classes unique to each situation, but that seems extremely verbose and clumsy.
Note: In the interest of brevity, my sample code above has no error checking, no null checking and may even have minor errors (e.g. treating const char * as a string ;-).
Below is the std::bind(..) example for what you're trying to do in C++11. For earlier C++ versions you could use the boost::bind utilities.
Fix your MyVisitor::VisitExit(...) method to return a boolean, by the way.
The code is converting const char * to std::string. tinyxml2 does not guarantee that the char * arguments from Name() or GetText() are not null. In fact in my experience they will be null at some point. You should guard against this. For the sake of not modifying your example too much I've not protected against this possibility everywhere in the example.
typedef bool(*Callback)(string, string);
using namespace std;
class MyVisitor : public tinyxml2::XMLVisitor {
public:
bool VisitExit(const tinyxml2::XMLElement &e) {
// return callback(e.Name(), e.GetText());
return true;
}
Callback callback;
};
/** Typedef to hopefully save on confusing syntax later */
typedef std::function< bool(const char * element_name, const char * element_text) > visitor_fn;
class MyBoundVisitor : public tinyxml2::XMLVisitor {
public:
MyBoundVisitor(visitor_fn fn) : callback(fn) {}
bool VisitExit(const tinyxml2::XMLElement &e) {
return callback(e.Name() == nullptr ? "\0" : e.Name(), e.GetText() == nullptr ? "\0": e.GetText());
}
visitor_fn callback;
};
bool
myCallBackFunc(string e, string v) {
cout << "Element " << e << " has value " << v << endl;
return true;
}
int
main()
{
tinyxml2::XMLDocument doc;
doc.LoadFile("somefile.xml");
MyVisitor visit;
visit.callback = myCallBackFunc;
doc.Accept(&visit);
visitor_fn fn = myCallBackFunc; // copy your function pointer into the std::function<> type
MyBoundVisitor visit2(fn); // note: declare this outside the Accept(..) , do not use a temporary
doc.Accept(&visit2);
}
So from within the ServiceClass method you'd do:
ServiceClass::processResponse(string xml) {
// Parse XML and do something only if certain elements present.
tinyxml2::XMLDocument doc;
doc.Parse(xml.c_str(), xml.length());
// presuming changeState(const char *, const char *) here
visitor_fn fn = std::bind(&ServiceClass::changeState,this,std::placeholders::_1,std::placeholders::_2);
MyBoundVisitor visit2(fn); // the method pointer is in the fn argument, together with the instance (*this) it is a method for.
doc.Accept(&visit);
}
You can use generics in order to support whichever callback you'd like.
I've tried to mock the classes of the library in order to give you a fully runnable example:
#include <string>
#include <iostream>
#include <functional>
class XmlNode {
public:
XmlNode(const std::string& n, const std::string t) : name(n), txt(t) {}
const std::string& Name() const { return name; }
const std::string& GetText() const { return txt; }
private:
std::string name;
std::string txt;
};
class XMLVisitor {
public:
virtual void VisitExit(const XmlNode& node) = 0;
virtual ~XMLVisitor() {}
};
template<typename T>
class MyVisitor : XMLVisitor {
public:
MyVisitor() {}
void myInnerPrint(const XmlNode& node) {
std::cout << "MyVisitor::myInnerPrint" << std::endl;
std::cout << "node.Name(): " << node.Name() << std::endl;
std::cout << "node.GetText(): " << node.GetText() << std::endl;
}
void SetCallback(T newCallback) {
callback = newCallback;
}
virtual void VisitExit(const XmlNode& node) {
callback(node);
}
T callback;
};
int main() {
XmlNode node("In", "Member");
MyVisitor<std::function<void(const XmlNode&)>> myVisitor;
auto boundCall =
[&myVisitor](const XmlNode& node) -> void {
myVisitor.myInnerPrint(node);
};
myVisitor.SetCallback(boundCall);
myVisitor.VisitExit(node);
return 0;
}
First define a template and a helper function:
namespace detail {
template<typename F>
struct xml_visitor : tinyxml2::XMLVisitor {
xml_visitor(F&& f) : f_(std::move(f)) {}
virtual void VisitExit(const tinyxml2::XMLElement &e) {
f_(e);
}
private:
F f_;
};
}
template<class F>
auto make_xml_visitor(F&& f)
{
return detail::xml_visitor<std::decay_t<F>>(std::forward<F>(f));
}
Then use the helper function to construct a custom visitor from a lambda which captures this:
void ServiceClass::processResponse(std::string xml) {
// Parse XML and do something only if certain elements present.
tinyxml2::XMLDocument doc;
doc.Parse(xml.c_str(), xml.length());
auto visit = make_xml_visitor([this](const auto& elem)
{
this->changeState(elem.Name(), elem.GetText);
});
doc.Accept(std::addressof(visit));
}
The rule is that a function pointer must always accept a void * which is passed in to the module which calls it, and passed back. Or use a lambda which is the same thing with some of the machinery automated for you. (The void * is the "closure").
So
typedef bool (*Callback)(string, string, void *context);
class MyVisitor : public tinyxml2::XMLVisitor {
public:
bool VisitExit(const tinyxml2::XMLElement &e) {
callback(e.Name(), e.GetText(), contextptr);
}
Callback callback;
void *contextptr;
}
bool myCallBackFunc(string e, string v, void *context) {
ServiceClass *service = (ServiceClass *) context;
cout << "Element " << e << " has value " << v << endl;
service->ChangeState(e, v);
return true;
}

What is the syntax for storing a specific class's member functions in a vector?

I did quite a bit of searching, but the combination of * () and class scope has greatly hindered me in understanding of the syntax, with each edit throwing a new error, any help guys?
What I'm trying to do:
Declare a std::vector of pointers to member functions found in MyClass.h
Assign the actual member functions to the std::vector in MyClass.cpp's constructor
The member functions are not static
Thanks!
I'm curious where you're going to use them from. You see in order to call a C++ class member function you need to have an instance pointer with which to call it (each member function needs a this in order to access the class state). So normally you'd wrap the member function pointer together with the instance pointer with std::bind and then maybe store the result in std::function. To put them in vector they're all going to need the same signature.
Is this the kind of thing you were looking for:
class P
{
typedef std::function<void (void)> func_t;
std::vector<func_t> functions;
public:
P()
{
functions.push_back(std::bind(&P::foo1, this));
functions.push_back(std::bind(&P::foo2, this));
functions.push_back(std::bind(&P::foo3, this));
}
void foo1(void)
{
std::cout << "foo1\n";
}
void foo2(void)
{
std::cout << "foo2\n";
}
void foo3(void)
{
std::cout << "foo3\n";
}
void call()
{
for(auto it = functions.begin(); it != functions.end(); ++it)
{
(*it)();
}
}
};
int main()
{
P p;
p.call();
}
After further clarification from the OP I'll propose this:
class P
{
typedef std::function<void (void)> func_t;
std::map<const char*, func_t> functions;
public:
P()
{
functions["foo1"] = std::bind(&P::foo1, this);
functions["foo2"] = std::bind(&P::foo2, this);
functions["foo3"] = std::bind(&P::foo3, this);
}
void foo1(void)
{
std::cout << "foo1\n";
}
void foo2(void)
{
std::cout << "foo2\n";
}
void foo3(void)
{
std::cout << "foo3\n";
}
void call_by_name(const char* func_name)
{
functions[func_name]();
}
};
int main()
{
P p;
p.call_by_name("foo1");
p.call_by_name("foo2");
p.call_by_name("foo3");
}
You can use member function pointers like this (the C++11 is unrelated to that part):
struct S {
int foo(){std::cout<<"foo"; return 0;}
int bar(){std::cout<<"bar"; return 0;}
};
int main() {
std::vector<int(S::*)()> funcs{&S::foo, &S::bar};
S s;
for (auto func : funcs) {
(s.*func)();
}
}
However, if you use C++11, std::function can make it a bit cleaner:
std::vector<std::function<int(S &)>> funcs{&S::foo, &S::bar};
S s;
for (auto func : funcs) {
func(s);
}
If you use C++03, Boost has boost::function, which is similar.