Robert Driller
Robert Driller

Reputation: 87

Access a Class Object inside a static restbed handler

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!!

Upvotes: 0

Views: 279

Answers (2)

ficus
ficus

Reputation: 55

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));

Upvotes: 0

Alexandru Smeu
Alexandru Smeu

Reputation: 36

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.

Upvotes: 0

Related Questions