I am currently getting familiar with restbed for a project but ran into a problem right at the start. I admit that this might be something very trivial but still a problem for me at the time.
Restbed service requires a const callback function
void set_method_handler( const std::string& method, const std::function< void ( const std::shared_ptr< Session > ) >& callback );
The thing is that I wand to create a REST service to GET some data from a class object.
HEADER
std::shared_ptr<restbed::Resource> REST_get_test;
static void get_test_handler(const std::shared_ptr< restbed::Session > session );
CONSTRUCTOR
REST_get_test = std::make_shared< restbed::Resource >( );
REST_get_test->set_path( "/test" );
REST_get_test->set_method_handler( "GET", get_test_handler);
The handler I call is supposed to iterate through a structure (Code is not finished, but enough to illustrate the problem)
void c_module_home::get_test_handler( const std::shared_ptr< restbed::Session > session )
{
QJsonObject status;
for (auto iter = cortexDrones.begin(); iter!= cortexDrones.end(); ++iter){
}
session->close( restbed::OK, "Hello, World!", { { "Content-Length", "13" }, { "Connection", "close" } } );
}
As expected I get a:
error: invalid use of member 'project::c_module_home::cortexDrones' in static member function
Does anyone have a suggestion how to handle that? Thanks a lot!!
Long story short... it's not a very trivial problem; at least the answer behind why it's not working as expected.
get_test_handler is a static member function in a class and it cannot access non-static properties.
If get_test_handler is a non-static member function in a class it cannot function as a callback, because a member function pointer is not the same as a "normal" function pointer.
Member functions expect the this pointer to be passed as first parameter. This is done by the compiler automatically; meaning that the function signatures do not match.
In my first attempts at mainly the same thing (using restbed), on of the first thoughts was to make the handler static, but that forces you to have anything else you might access from the handler be static as well. This is not a solution in my opinion.
The solution I found after some struggling with the same problem is to wrap the handler in a lambda function; at least if you're using C++11 or greater.
Short example based on your code:
resource->set_method_handler("GET",
[&](const std::shared_ptr<restbed::Session> session) {
get_test_handler(session);
});
Main point here is not to get the idea that a lambda is a std::function; it's an unspecified type which can be assigned to a std::function (of course the type has to match).
You can find more details in the following links:
https://en.cppreference.com/w/cpp/language/lambda
https://shaharmike.com/cpp/lambdas-and-functions/
UPDATE:
I found this link which in my opinion describes best C++ lambdas: https://www.cprogramming.com/c++11/c++11-lambda-closures.html and it's a way easier read compared to the cppreference.com one.
I know this is already answered but if you do not want to use lambdas you can use std::bind.
Short example based on your code:
resource->set_method_handler("GET",std::bind(&c_module_home::get_test_handler, this, _1));
Related
I'm working on a project in C++, but at some point in the application it fails and generates a core dump. The application uses a couple of classes, which for the purposes here I'm concentrating on one of the classes, which I'm calling A, and is instantiated as object a. This has a large number of member functions, of which at the moment only a few are being used, but one of these generates a log to produce diagnostics to be used for debugging. I want to use this to find out why the application is failing.
The project is to put together code that invokes the various member functions, and although I have access to the source code and some limited documentation, none of the code can be changed, with all changes being in the code that makes use of the classes and invokes the member functions. The member function in question is:
void enable_log (log_callback callback, void * user_data = nullptr)
where the 1st argument callback contains the message and 2nd argument is optional. For now it can be set to nullptr, so would be invoked as:
a.enable_log(callback, nullptr);
From this documentation it's not at all clear what exactly callback is. However, in looking at the source code this is:
using log_callback = void (*)(const std::string& message, void* user_data);
in a header file, where log_callback is an alias for const std::string& if I understand this correctly.
I already have dummy classes on a platform using Visual Studio 2019 with some test member functions to simulate invoking the member functions on a remote Linux server, but I'm unable to find a way of making use of the member function above. I added the test member function to the dummy class as follows:
void enable_log(const std::string& callback, void* user_data = nullptr) {
callback = "ABCD";
}
which is supposed to generate a test string which is returned, such that in the real application this string will have diagnostic information that will be written to a file. However, the "=" is an error.
The idea is that in the main function an empty string will be declared, then enable_log() should populate this string, which can be printed out.
I've spent some time looking at various resources, including Stackoverflow, but I cannot find a way of returning a string with the information that can be printed out. I need a simple way to simulate this, and as I said above, I must not change the source code of the real member function, so the simulated member function has to produce a string in the same way. How is this done? Some advice would be appreciated.
Callback, in simple words, is some function that will be called later at some point. Example:
void callback_fn(int a);
using callback_t = (void)(*)(int a);
void some_func(callback_t);
You can use some_func() like so:
some_func(callback_fn);
Full example here: https://godbolt.org/z/ET3GhfYrv
For your usecase the parameters of the callback are slightly different. Here's how to read the syntax:
using log_callback = // this just creates an alias for whatever is on the right handside
void // the return type of the "callable" should be void
(*) // this tells us that it is a function pointer
(const std::string& message, void* user_data) // These are the arguments the callable takes. It is a "std::string" and a "void *"
To use this, just create a free function with the same signature:
void callable(const std::string &msg, void *userData = nullptr)
{
// msg is the data sent by the function. use it in whatever way
// you want.
std::cout << msg << '\n';
}
// Pass it to the enable_log
enable_log(callable);
This is mainly to clean up a bunch of code from my constructor. I have around 20+ lines of connect(object, func1, this, func2) in the constructor alone and I am trying to clean up the code by having a std::vector<std::tuple<QObject*,std::function<void()>,std::function<void>>>> connections;
It would work out quite nicely if I could do something like:
std::vector<std::tuple<QObject*,std::function<void()>,std::function<void>>>> connections = {
std::make_tuple(mySlider, std::bind(&QSlider::sliderReleased,mySlider, std::bind(&Foo::onSliderChanged,this)),
.
.
.
};
And then call it like this:
for(auto &&e : connections)
connect(std::get<0>(e),std::get<1>(e),this,std::get<2>(e));
However, when I do this I get an error that there is a substitution failure and a std::function<void()> cannot be converted into a function pointer. So decide to change it up and create actual function pointers like the following:
typename void(Foo::*fooFunc)();
typename void(QSlider::*sliderFunc)();
std::vector<std::tuple<QObject*,sliderFunc,fooFunc>> sliderConnections = {
std::make_tuple(mySlider, &QSlider::sliderReleased, &Foo::onSliderChanged),
.
.
.
};
And same thing, I then try to call it:
for(auto &&e : sliderConnections)
connect(std::get<0>(e),std::get<1>(e),this,std::get<2>(e));
However this also provides a similar error where there are no conversions. Which doesn't make any sense because now I am actually using a function pointer. Which according to the connection documentation it should be able to take a function pointer to connect them. So either I am passing it in incorrectly. Or what I am trying to achieve is not possible.
Any help would be appreciated!
After looking at G.M's comment I realized they were correct. A QObject* is not a QSlider* and therefore when trying to call the function QSlider::sliderReleased it couldn't connect the two because QObject does not have a slider. So once I changed that in the vector of tuples the code compiled just fine.
ex:
typedef void(Foo::*fooFunc)();
typedef void(QSlider::*sliderFunc)();
typedef void(QSpinBox::*spinFunc)();
const std::vector<std::tuple<QSlider*, sliderFunc, fooFunc>> sliderConnections = {
std::make_tuple(slider1, &QSlider::sliderReleased, &Foo::onSlider1Changed),
std::make_tuple(slider2, &QSlider::sliderReleased, &Foo::onSlider2Changed),
std::make_tuple(slider3, &QSlider::sliderReleased, &Foo::onSlider3Changed)
};
const std::vector<std::tuple<QSpinBox*, spinFunc, fooFunc>> spinConnections = {
std::make_tuple(spin1, &QSpinBox::editingFinished, &Foo::onSpin1Changed),
std::make_tuple(spin2, &QSpinBox::editingFinished, &Foo::onSpin2Changed),
std::make_tuple(spin3, &QSpinBox::editingFinished, &Foo::onSpin3Changed)
};
These will be private members in whatever class you are in charge of. And then in the constructor, instead of having 6 lines of connect(object,SIGNAL,object,SLOT), you can then put them into a function and call them like:
for(auto && tup : sliderConnections)
connect(std::get<0>(tup),std::get<1>(tup),this,std::get<2>(tup));
This successfully connects all the objects to their appropriate functions. Again, it's personal preference. I was just wondering if there was a way and G.M pointed me in the correct direction.
I'm creating a 2D RPG game engine in C++ with Allegro. I've reached the point in which i need to implement a scripting system. So, my poblem is this one:
I have a struct called Event. Inside this struct there is a function pointer, which points to the function that i want to execute when the event is fired. So, here's an example:
struct Event {
//...
void (*func)(Player*, void*);
//...
}
Now, to create an event i have this function:
Event* Events::register_event_source(int x, int y, std::string name, Player* player, void (*func)(Player*, void*));
So, to use it i just need to create a function with this signature:
void test_event(Player* p, void* data)
{
//Do something cool here
}
and then register an event source, giving the address to that function:
//...
Player* player = new Player(0, 0);
//...
Event* evt = Events::register_event_source(10, 10, "test event", player, &test_event);
//Eventually set some data for the event
evt->set_data(new std::string("Just some test data"));
In this way, when the player goes over the assigned spot (in this case x = 10, y = 10) the event will fire, executing any code in the test_event function.
Now, my question is: is it possible to do, or at least to get close to, this process at runtime?? ...i would need to create the function (in this case "test_event") at runtime, but i did some research, and i think what i understood is that it is not really possible to create functions at runtime.
So, which approach should i go for?? ...I know it is an abstract question...but i really don't know how to approach this problem.
Thanks in advice for any help! and sorry for my bad explaining abilities...English is not my language!
If I understand correctly what you are trying to express, you are writing a scripting engine that interprets some logics built at run-time into a string, and this should determine what to do on Player and data. If so, I can imagine you should have a function like
void InterpretScriptCode(Player* p, void* data, string const& code)
or something equivalent that interprets and execute the logics described in code on p and data.
Then, you can use std::bind and std::function to encapsulate a call to your scripting engine:
// Header <functional> needs to be included, and a proper "using namespace"
// directive must be present for bringing placeholders _1 and _2 into scope
std::function<void(Player*, void*)> fxn = std::bind(
&InterpretScriptCode,
_1,
_2,
"int x = 0; ... blah blah" // this should be your run-time generated script
);
And pass fxn in input to your register_event_source() function.
Btw, you might be interested in using Boost.Signals/Boost.Signals2 for realizing event registration/handling.
If you are not using C++11, you can use boost::bind and boost::function instead of std::bind and std::function.
I'm having some trouble making a callback wrapper class method that needs to be used by a third party library; the JackAudio library.
I have been able to make a wrapper for a JackAudio callback function that needs two arguments.
I'm just having trouble creating a callback function for a particular function that needs a const char * as an argument.
So far I have been able to make the JackAudio library jack_set_sample_rate_callback function use a custom class and can be executed like so:
SoundClass Sound;
SoundClass * SoundPointer = &Sound;
jack_set_sample_rate_callback(
client,
SoundClass::SampleRateCallbackWrapper,
SoundPointer
);
And the class looks something like this:
SoundClass
{
int SampleRateCallback( jack_nframes_t nframes )
{
//executes some code when called.
}
static int SampleRateCallbackWrapper( jack_nframes_t nframes, void * arg )
{
return static_cast < SoundClass* > ( arg )->SampleRateCallback( nframes );
}
};
All of the above works well, with no issues.
The problem I'm having now is with the JackAudio callback function jack_set_error_function
This is what I tried:
static void ErrorCallbackWrapper( const char * arg )
{
return static_cast < SoundClass*>( arg )->SomeErrorFunction();
}
But I get error: invalid static_cast from type ‘const char*’ to type ‘SoundClass*’
I get the gist why this is happening, I just have no idea what to do for a solution.
Thanks in advance for any help guys.
Assuming the Jack API is written for the C language, there is a formal problem already with the working callback that you have. Namely that it then needs to be extern "C", and that as a static member function it cannot be. So formally it needs to be a free-standing function.
The documentation that you link to for the jack_set_error_function gives this signature, presumably expressed in C:
void jack_set_error_function( void(*)(const char *) func);
For C++ the callback must be assumed to be extern "C", so,
extern "C" void MyErrorFunction( char const* errorMessage )
{
// Whatever, e.g. post a message to the GUI event queue, or terminate.
}
If you want this function to in turn call a method on an object, then unless the library provides some special mechanism to help you, you will just have to use one of the following techniques:
a namespace scope variable accessed by the callback, or
a dynamically generated callback.
C++ does not as of yet support the second approach, at all, so the first one is strongly indicated – if you want a callback on a method of an object.
EDIT: Sorry, I forgot to mention,
the function declarations in the API documentation are syntactically invalid.
E.g. the documentation’s signature
void jack_set_info_function( void(*)(const char *) func );
simply won’t compile with a standard-conforming compiler. Not as C, and not as C++. It’s syntactically invalid in both languages.
Instead it should be
void jack_set_info_function( void(*func)(const char *) );
Since the documentation apparently is generated by DOxygen, it stands to reason that it's been generated from source code that compiles. If so then this is a bug in DOxygen, and a problem with the quality assurance of the library provider. However it might be a problem that lies solely with the library provider, or, I might be mistaken in the assumption that this is a C library?
First, some background:
(Note: Though I'm in non-.NET Win32 land, this is really a C++ question)
I'm using a 3rd party API which requires you to register a callback function in order to know when an async operation is complete. Gotta use the callback, no way around it.
A non-OOP implementation would be something like this:
void __stdcall MyCbFcn(int value)
{
do something with 'value'...
}
API_RegisterCallback(MyCbFcn);
Pretty standard stuff.
BUT...
My code is OOP, with multiple instances rx'ing the callback, thus the callback needs to be routed to the object that registered it.
Knowing that folks do this, callbacks typically include a user var, something like:
void __stdcall MyCbFcn(int value, U32 user)
{
do something with 'value'...
}
API_RegisterCallback(MyCbFcn, someUserValue);
and more specifically, when combined with OOP, this user arg allows you to get back into context:
(written inline for brevity):
class MyClass
{
public:
MyClass()
{
API_RegisterCallback(MyClass::StaticCbFcn, (U32)this);
}
private:
static void __stdcall StaticCbFcn(int value, U32 user)
{
MyClass* pThis = (MyClass*)user;
pThis->InstanceCbFcn(value);
}
void InstanceCbFcn(int value)
{
... do some work in context ...
}
}
BUT, my API doesn't feature a user arg :(
So now my question:
How I can get back into context?
I've considered kinda sketchy things like defining a "pool" of 100 distinct callbacks and assigning them as objects are created, but that seems like a real hack.
An obvious solution ... if I were in e.g. JavaScript :) ... would be to use an anonymous function, but AFAIK C++ doesn't have anything like that.
Any ideas would be appreciated.
"100 distinct callbacks" is really the only thing you can do, thus you use the function address as identifying parameter. It might help to implement the different functions as template with a constant parameter:
template < unsinged N >
void StaticCbFcn( int value )
{
map[ N ].InstanceCbFcn( value );
}
You can do this with boost bind:
boost::bind(&my::function_to_call_cb, this, _1, context));
void my_impl::function_to_call_cb(int result, std::string context)