I'm trying to find a way to provide pointers to a member functions between different class instances. For the moment I'm able to provide pointers to member function that takes no arguments but cannot manage to do so when the function to point to has an argument.
A sample code to illustrate my problem :
#include <iostream>
class Event
{
public:
std::string type;
Event(std::string type):type(type){}
};
class EventDispatcherBase
{
public:
void addEventListener(std::function<void(Event &event)> listener)
{
Event myEvent("Type of the myEvent object");
listener(myEvent);
}
};
class EventDispatcherClass:public EventDispatcherBase
{
public:
EventDispatcherClass()
{
addEventListener([](Event &event){std::cout << event.type << std::endl;});
//addEventListener([this]{listener(Event event);});
};
void listener(Event &event)
{
std::cout << event.type << std::endl;
}
};
int main()
{
EventDispatcherClass eventDispatcherClass;
return 0;
}
This code works with an anonymous lambda expression and output "Type of the myEvent object" in the console. But if I uncomment the line
addEventListener([this]{listener(Event event);});
in the constructor of the EventDispatcherClass in order to transmit a pointer to the void listener(Event &event) member function, the compiler throw the following error :
no viable conversion from '(lambda at .../main.cpp:27:26)' to
'std::function'
I don't understand why.
but cannot manage to do so when the function to point to has an argument.
The lambda should take an argument of type Event&, which will be forwarded to the member function inside the lambda. So change it to
addEventListener([this](Event &event){listener(event);});
// ^^^^^^^^^^^^^^
LIVE
The working line:
addEventListener([](Event &event){std::cout << event.type << std::endl;});
looks nothing like the broken one:
//addEventListener([this]{listener(Event event);});
so start by changing the working line bit by bit.
add the capture expression you will want, and it still works
addEventListener([this](Event &event){std::cout << event.type << std::endl;});
change the body to the one you want, and it still works
addEventListener([this](Event &event){ this->listener(event); });
If you're having trouble seeing what's different between the two versions - which is actually pretty common when you wrote them yourself and you're seeing what you intended to type instead of what's there - try changing the layout to line everything up (so you'd see the missing (Event &event)), or transforming one into the other step-by-step as above, or just replace one with the other and diff the file versions.
just change it to addEventListener(listener);
and make the function itself static as static void listener(Event &event)
Related
I created two files, Linkage.cpp and External.cpp.
Linkage.cpp:
#include <iostream>
void Log(int x = 5)
{
std::cout << x << "\n";
}
int main()
{
Log();
return 0;
}
External.cpp:
#include <iostream>
void Log(const char* message)
{
std::cout << message << "\n";
}
Why am I not getting a linker error? Both these functions are defined in the global namespace, so there should be naming conflicts as with variables.
Why am I not getting a linker error?
When you wrote
void Log(int x = 5)//this means that the function named Log can be called without passing
//any argument because you have provided a default argument which will be
//used in case you don't provide/pass any argument
{
//..other code here
{
The above means that the function named Log can be called without passing any argument because you have provided a default argument which will be used in case you don't provide/pass any argument.
Next when you wrote
void Log(const char* message)//this means that this versoin of the function named Log will be called only if you pass an argument of type `char*` .
{
std::cout << message << "\n";
}
The above means that this verion of the function named Log will be called only if you pass an argument of type char* .
Now when your wrote:
Log();
The first version which has a default argument will be used because you haven't provided any argument and so the first version can be used(since it is viable) and because the second version which must take an argument is not viable.
Okay, I experimented around after #Retire Ninja pointed this out to me.
First, comment out all the code from External.cpp. Now, declare another Log function inside Linkage.cpp so that there are two functions inside this file that have the same name(Log) but different parameters. You will realise that using depending upon what arguments you supply, these Log functions will behave like different functions.
So, unlike variables, where same name means same variable in a namespace, functions need to have matching signatures too.
My system defines multiple unordered_map-like data, e.g.
std::unordered_map< int, int> int_map;
std::unordered_map< int, double> double_map;
std::unordered_map< string, string> string_map;
std::unordered_map< string, string> string_map_2;
...
std::unordered_map< string, vector<string> > string_string_map;
std::unordered_map< string, vector<string> > string_string_map_2;
Each map holds different data types. These are used with a framework (written in C) that registers callback functions. The registration function (register_undo_handler) takes two arguments: a pointer to the callback function and data to be passed to the callback. In our case, the data is a map pointer.
//register our callback function to UNDO framework
register_undo_handler(clear_data, &int_map);
//or :
register_undo_handler(clear_data, &string_map);
// this is a sketch of the callback function, which frees the map resources
void clear_data(void *data)
{
data->clear();
}
If an UNDO happens, the UNDO framework will call each defined callback function, e.g. clear_data, and pass the registered data, cast to void*, as the parameter like this
// For each registered callback function, run with registered parameter
(*registered_callback_func)(data);
We want to have a single callback function that can free any map.
Any suggestion on the implementation?
you can have single template to do it if you just don't want to dupe code.
#include <functional>
#include <unordered_map>
#include <iostream>
using namespace std;
void register_undo_handler(void(*callback)(void*), void* data){
callback(data); //I'd not gonna implement all undo in C so let me do this instead
}
template<typename clearable>
void Erase(void* data){
((clearable*)data)->clear();
}
int main(){
std::unordered_map<int, int> int_map;
std::unordered_map<int, double> double_map;
double_map[0] = int_map[0] = 0;
//you can wrap this into a function to avoid type types yourself
register_undo_handler(&Erase<decltype(int_map)>, (void*)&int_map);
register_undo_handler(&Erase<decltype(double_map)>, (void*)&double_map);
std::cout << int_map.size() << ' ' << double_map.size();
}
When an "undo" callback is invoked, there are two pieces of information available, namely the address of the function to call and the pointer-sized data to provide to the function. Your requirement is for the first piece to not vary, so it is up to the second piece to tell us what type of map is involved. A big problem is that once a pointer is cast to void*, there is no longer a way to recover its original type. So to accomplish the stated goal, you would need a way to identify the map with something other than a raw pointer. One possibility is wrapping the pointer in an object that could remember the original type. This can get messy, especially if you need to dynamically allocate these wrapper objects. The overhead for coding this is more than for writing multiple callback functions. Similarly, there is no savings in runtime overhead (neither time nor space). This is probably not what you want to do.
It is much simpler to write a callback for each type. It takes only a few lines of code to define the callbacks. Each function compiles into a small amount of object code; taken together, the compiled functions are almost the theoretical minimum amount of object code required for any solution. (Each map type's clear function is a distinct function, so it takes distinct function calls to potentially call each of them. I'm above the minimum because I check for null.)
template <class T>
void call_clear(void * ptr)
{
if ( ptr )
static_cast<T*>(ptr)->clear();
}
Registering one of these callbacks is a bit of a syntactic pain (e.g. register_undo_handler( call_clear<decltype(int_map)>, &int_map);), so it might be desirable to write a wrapper to handle the registration. This wrapper can deduce the template parameter, reducing the amount of repetitive typing. The compiler should inline this function at any level of optimization, resulting in no additional runtime overhead.
template <class T>
void register_undo_call_clear(T & map)
{
register_undo_handler(call_clear<T>, &map);
}
At this point, registering the callback is done simply with, for example, register_undo_call_clear(int_map);.
EDIT :
I just realize it's not easier than write every callback function (which still needs to be done) if it's only to clear those map... I'd leave this here as a reference for general-propose handler to C handler solution. (btw technically it does only need one callback function(1st parameter) 😑 )
First, I'd strongly suggest move to a c++ undo framework
But you can actually archive this with single handler (1st parameter).
The point is use a type-erased handler (std::function at below code) passed as data (2nd parameter), and invoke it at the wrapper handler (1st parameter)
note: you still not adding the signature of register_undo_handler so I guess it's
void register_undo_handler(void(*)(void), void*);
The code ( Wandbox )
#include <functional>
#include <list>
#include <stack>
#include <iostream>
using namespace std;
void register_undo_handler(void(*callback)(void*), void* data){
callback(data); //I'd not gonna implement all undo in C so let me do this instead
}
void the_callback_wrapper(void* cb){
(*static_cast<function<void()>*>(cb))();
}
int main(){
list<function<void()>> undos;
//and your maps, they should have same lifetime
int a=2,b=3;
//do something...
undos.emplace_back([]{std::cout << "I'd like to undo this - 1\n";});
register_undo_handler(the_callback_wrapper, (void*)(&undos.back()));
//undo with local variables, no problem
undos.emplace_back([&]{std::cout << "I'd like to undo this - " << a << '\n';});
register_undo_handler(the_callback_wrapper, (void*)(&undos.back()));
undos.emplace_back([&]{std::cout << "I'd like to undo this - " << b << '\n';});
register_undo_handler(the_callback_wrapper, (void*)(&undos.back()));
//modify local variable, no problem
undos.emplace_back([&]{std::cout << "I'd like to modify a to 100\n"; a=100;});
register_undo_handler(the_callback_wrapper, (void*)(&undos.back()));
std::cout << "a should be 100 : a = " << a << '\n';
//use multiple local variable, no problem
undos.emplace_back([&]{std::cout << "I'd like to modify **both a and b** to 10000\n"; a=b=100000;});
register_undo_handler(the_callback_wrapper, (void*)(&undos.back()));
std::cout << a << ' ' << b;
}
sidenote: If you can use global variable to store whose undo functors, you can also pass their index as data and let the callback decide which functor to call.
EDIT:
I have modified the example API so it better reflects the real API I am dealing with. The way the API get's the message argument passed to it is by user input so the message argument cannot be used to pass additional data.
I am dealing with a very frustrating API that uses callback routines that don't take "void* userarg" pointers.
Assuming the function that uses the callback routine as defined by the API expects a string argument (that will be assigned by user input), is there ANY possible way to get more data into my callback routine without using global variables?
Here is a simplified example of what the API might look like:
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////////////////////
// ASSUME EVERYTHING IN THIS SECTION IS PART OF AN API AND IS NOT MY OWN CODE...
// I DO NOT HAVE THE SOURCE AND IT CANNOT BE MODIFIED
typedef void (*CALLBACK)(string message);
void call_callback(CALLBACK cb) {
// Gets a message from user input
string message = "hello"; // pretend this is user input
cb(message);
}
////////////////////////////////////////////////////////////////////////////////
int data = 42;
void callback_function(string message) {
// I want to access "data" here WITHOUT it being global
cout << message << ' ' << data << endl;
}
int main(int argc, char** argv) {
call_callback(&callback_function);
}
Typically an API that uses callbacks would also pass a "void* userarg" argument into the callback routine so you could pass additional data of any type, but that is not the case here.
This API is used extensively throughout our whole codebase and it is 100% necessary to pass a lot more data in every case where it is used. The current way we get more data in *prepare to cringe* is by storing practically all of our data in singletons so nearly everything is global and can be accessed from literally anywhere in the program.
This whole concept seems EVIL to me, but without a better API I can't figure out any better way to get the data into the callback. I have already contacted the vendor and asked that they fix their API to make it accept a "void* userarg" argument, but it doesn't look like it will be fixed anytime in the near future...
All I am hoping for is ANY better way of doing things than we are now.
If it is really an std::string which is an argument to the callback (and not something else) and you really have access to the argument (as in your sample code which invokes call_callback with supplied string) you can put an entity-serialized pointer to your allocated object into std::string (which is allowed to have arbitrary data in it) and invoke call_callback with it.
One challenge here would be the fact that you'd than have to manually manage this pointer.
My most straightforward idea would be to provide unique strings in place of the void* you would normally expect. You'd then have one map singleton that maps the strings to your callbacks.
So something like this:
class Dispatcher
{
public:
// TODO: Thread safety etc.
std::string makeCallback(std::function<void()> callback)
{
std::string uid = std::to_string(_index);
_callbacks[uid] = std::move(callback);
_index++;
return uid;
}
void runCallback(std::string uid)
{
_callbacks[uid]();
}
private:
size_t _index = 0;
std::map<std::string, std::function<void()>> _callbacks;
};
void leaveAPI(std::string uid)
{
getSingleton<Dispatcher>()->runCallback(uid);
}
void enterAPI(std::function<void()> userCallback)
{
std::string uid = getSingleton<Dispatcher>()->makeCallback(userCallback);
call_callback(leaveAPI, uid);
}
Demo
You just count up a number every time you call the API and use its string version as the callback parameter. The class also maps each of those strings to the callback you wanted called. You could remove the map entries or do any number of performance optimizations, but this is the gist of it.
(This would work just as well with const char* if you figure out the ownership/lifetime questions that it opens.)
You should really petition the writers of the API to use std::function instead of raw pointers to functions.
Then you can easily use e.g. std::bind or lambda expressions to be able to call functions taking more arguments than the callback takes.
For example:
// The callback is a function taking one string argument, and return nothing
using CALLBACK = std::function<void(std::string)>;
// Do some processing and then call the callback function
void call_callback(CALLBACK cb, std::string message)
{
// ...
cb(message);
}
// Our callback takes a string *and* an integer argument
void callback_function(std::string message, int data)
{
std::cout << message << ' ' << data << '\n';
}
int main()
{
int local_data = 42;
// Using std::bind...
using namespace std::placeholders; // for _1, _2, _3...
call_callback(std::bind(&callback_function, _1, local_data), "Foobar");
// Using lambdas...
call_callback([local_data](std::string message)
{
callback_function(message, local_data);
}, "Foobar");
}
Using std::function also makes it easy to use member functions as callbacks as well, not only non-member functions (or static member functions).
However, if you can't modify the API, or the creator of it won't change it and it have to use C-style plain pointers to non-member functions, you can still solve it with lambdas, but you can't have any captures for the lambda:
call_callback([/*empty!*/](std::string message)
{
// Call the function as defined in the previous snippet
callback_function(message, 42); // Pass the value directly
}, "Foobar");
Actually I am new to writing handlers but somehow i managed to write this piece of code:
#include<iostream>
using namespace std;
class test
{
public:
typedef void (test::*MsgHandler)(int handle);
test()
{
cout<<"costructor called"<<endl;
}
void Initialize()
{
add_msg_Handler(4,&test::System);
}
void System(int handle)
{
cout<<endl<<"Inside System()"<<endl;
cout<<"handle:"<<handle<<endl;
}
protected:
MsgHandler message[20];
void add_msg_Handler(int idx,MsgHandler handler)
{
cout<<endl<<"Inside add_msg_Handler()"<<endl;
cout<<"handler:"<<handler<<endl;
message[idx]=handler;
cout<<"message:"<<message[idx]<<endl;
}
};
int main()
{
test obj;
obj.Initialize();
return 0;
}
This code is working fine, I get the output as:
costructor called
Inside add_msg_Handler()
handler:1
message:1
But there are several things beyond my scope. If I am right System() should have been called in this line:
add_msg_Handler(4,&test::System);
but this is not happening. I need help on rectifying this.
Second thing is, I am not able to understand why I am getting such output:
handler:1
I mean how does handler got initialized to 1.Can somebody help me in solving this??
&test::System is not a function call, it's a pointer to the member function test::System.
(A call would look like System(0) and wouldn't compile if you used it as the parameter in question.)
If you look at the definition of add_msg_handler:
cout<<endl<<"Inside add_msg_Handler()"<<endl;
cout<<"handler:"<<handler<<endl;
message[idx]=handler;
cout<<"message:"<<message[idx]<<endl;
there's not a single place that calls the function handler.
(A call would look like (this->*handler)(0) or (this->*message[idx])(0).)
So the function isn't called because there's nothing in your code that calls it.
The output is 1 because
handler is a pointer to a member function
there's no overload of << for pointers to member functions
there is an implicit conversion from pointer to member function to bool
there's an overload of << for bool
a non-null pointer is implicitly converted to true
true outputs as 1 by default.
I'm wrapping the Windows API, and I wish to make error checking easy to use, and helpful. Currently, I have a global error object, with a function set to handle a new error. The set function takes four arguments: bool Error::set (const int code, const char * file, const char * const function, const int line); The function uses the file, function, and line arguments to display them in a nicely formatted message.
To ease the setting of errors, there is a macro #define setError() error.set (GetLastError(), __FILE__, __FUNCTION__, __LINE__); This way I'm able to use setError() at any time to respond to an error that an API function has set by adding it after I call that API function.
Unfortunately, this causes the code to look something like this:
SomeAPIFunction();
setError();
AnotherAPIFunction();
setError();
There is also a problem with constructors:
MyClass:MyClass()
: a (SomeAPIFunction), b (AnotherAPIFunction)
{
setError(); //what if both functions set an error?
}
As you can see, by using member initializer syntax, I'm actually limiting myself.
One way to fix this would be to wrap every API function:
int someAPIFunction()
{
int ret = SomeAPIFunction();
setError();
return ret;
}
The function portion of the error message would tell me which function originated the error. Of course, that has to be the worst possible way of dealing with this.
The solution, it seems, is to use variadic templates. The problem is, I have no idea what I'm supposed to be doing to get them working for this. I'd imagine the final code looks something like one of the following:
wrap<int, SomeAPIFunction (5)>();
wrap<int, SomeAPIFunction, 5>();
wrap<int, SomeAPIFunction> (5);
I've read things on beginning variadic templates, but they've all left me clueless of how to set up something like this. Could anyone point me in the right direction?
I found the following on a similar question:
#include <iostream>
template<void f(void)>
struct Wrap {
void operator()() const {
std::cout << "Pre call hook" << std::endl;
f();
}
};
namespace {
void test_func() {
std::cout << "Real function" << std::endl;
}
}
const Wrap<&test_func> wrapped_test_func = {};
int main() {
wrapped_test_func();
return 0;
}
The respondent noted that variadic templates would be a necessity to make this generic enough. It's a start, but I'm lost and grateful of any help on the matter.
I think you'll be able to make it work with this syntax:
wrap(&SomeAPIFunction, arg1, arg2);
The key is to let the compiler use type deduction to determine the template type parameters, since they get pretty messy in a hurry.
The code should look something like:
template<typename TRet, typename... TArgs>
TRet wrap( TRet(WINAPI *api)(TArgs...), TArgs... args )
{
return api(args...);
}
Naturally, you'll want to use a macro to hide the address-of-function operator, use stringizing to store the function name, and store the filename and line number also, passing all of that to the actual variadic function. You'll need variadic macros for that. In fact, could you do all of this just with variadic macros and no templates?