This has got to be something simple, but I'm not experienced with C++ or bound functions. Basically I'm trying to do this:
server.on("/capture", HTTP_GET, std::bind(&SolarCamera::serverCapture, this, server));
The problem is when I use the server instance argument. Other similar binds without that instance are fine.
server is defined here as a protected method.
//SolarServer.hpp
class SolarServer
{
public:
SolarServer(int port);
void startRouter();
protected:
ESP8266WebServer server;
};
//SolarServer.cpp
SolarServer::SolarServer(int port): server(port){}
void SolarServer::startRouter() {
//capture cam
server.on("/capture", HTTP_GET, std::bind(&SolarCamera::serverCapture, this, server));
...
And all I want to do is pass that server instance to the SolarCamera class so I can return a camera stream to that instance. The camera interface is like this
// SolarCamera.hpp
class SolarCamera
{
public:
SolarCamera();
void serverCapture(ESP8S266WebServer& server);
protected:
ArduCAM myCAM;
};
But the compiler balks at the method invocation and dumps a gnarly log:
error: pointer to member t
ype 'void (SolarCamera::)(ESP8266WebServer&)' incompatible with object type 'SolarServer'
error: return-statement wi
th a value, in function returning 'void' [-fpermissive]
In your bind statement you're using this, which points to an instance of SolarServer, but, the method you're trying to bind to is of type SolarCamera. Instead of using this, you need to give it a reference to a SolarCamera instance.
Related
I am trying to use an Arduino library and to use one of it's functions as a parameter in my own function, but I don't know how can I do that.
I tried the code below but I get an error.
Any help will be appreciated.
P.S: I do not have an option to use auto keyword.
using namespace httpsserver;
HTTPServer Http;
typedef void (*Register)(HTTPNode*); // My typedef
Register Node = Http.registerNode;
When I am trying to call Node (...), I get the error below.
Cannot convert 'httpsserver::ResourceResolver::registerNode'
from type 'void (httpsserver::ResourceResolver::)(httpsserver::HTTPNode*)'
to type 'Register {aka void (*)(httpsserver::HTTPNode*)}'
How can I create a function pointer for the type :
'void (httpsserver::ResourceResolver::)(httpsserver::HTTPNode*)'
I want to use it as a parameter in another function:
// My Declaration
void Get(void(*Register)(httpsserver::HTTPNode*), const std::string& path);
// Usage
Get (Http.registerNode(...), ""); // Like so
How can I do that?
A member function pointer is not a function pointer.
typedef void (httpsserver::*Register)(HTTPNode*); // My typedef
Register Node = &httpsserver::registerNode;
usage:
void Get(void(httpsserver::*Register)(httpsserver::HTTPNode*), const std::string& path);
Get (&httpsserver::registerNode, "");
you have to pass the httpsserver::HTTPNode* into Register within Get.
If you want to bind the arguments to the function object and call it later, you want std::function<void()>:
void Get(std::function<void()>, const std::string& path);
Get ([&]{ Http.registerNode(...); }, "");
note, however, that this makes lifetime of the objects refered to within the {} above quite dangerous.
This question already has answers here:
C++ callback using class member
(6 answers)
Closed 2 years ago.
I am trying to make a server by looking at the sample code of cpprestSDK.
But I don't know why I bind in the sample code.
Below is the sample code.
stdafx.h
class Handler{
public:
Handler() {};
Handler(utility::string_t url);
pplx::task<void> open() { return m_listener.open(); }
pplx::task<void> close() { return m_listener.close(); }
private:
void handle_get(http_request request);
void handle_put(http_request request);
void handle_post(http_request request);
void handle_del(http_request request);
};
hander.cpp
#include "stdafx.hpp"
Handler::Handler(utility::string_t url) : m_listener(url)
{
m_listener.support(methods::GET, std::bind(&Handler::handle_get, this, std::placeholders::_1));
m_listener.support(methods::PUT, std::bind(&Handler::handle_put, this, std::placeholders::_1));
m_listener.support(methods::POST, std::bind(&Handler::handle_post, this, std::placeholders::_1));
m_listener.support(methods::DEL, std::bind(&Handler::handle_del, this, std::placeholders::_1));
}
Looking at the reference for support, it is defined as follows.
void support (const http::method &method, const std::function< void(http_request)> &handler)
I thought I could define it like this:
m_listener.support(methods::GET, &Handler::handle_get);
But it failed.
Can you tell me why I use "this" and "std::placeholders::_1" when doing a bind?
sample code : https://learn.microsoft.com/ko-kr/archive/blogs/christophep/write-your-own-rest-web-server-using-c-using-cpp-rest-sdk-casablanca
cpprestSDK listener reference : https://microsoft.github.io/cpprestsdk/classweb_1_1http_1_1experimental_1_1listener_1_1http__listener.html
The member function
void support (const http::method &method,
const std::function< void(http_request)> &handler)
expects handler to be a callable which has
an argument of type http_request
a return type void.
A plain function void handle(http_request) would match this required signature.
If you want to register a (non-static) member function this is also possible but you have to provide the object as well (as non-static member functions may not be called without object).
The std::bind(&Handler::handle_get, this, std::placeholders::_1) acts as (a kind of) adapter to fit your member function (with this as bound object) into that requirement.
The std::placeholders::_1 denotes, where to bind the argument (of type http_request) into the wrapped member function call.
A simpler way would be to use a lambda as adapter (instead of the bind):
m_listener.support(methods::GET, [this](http_request http_req) { this->handle_get(http_req); });
or even:
m_listener.support(methods::GET, [this](http_request http_req) { handle_get(http_req); });
Further readings:
std::bind
std::placeholders
GameObject class .h + .cpp:
typedef std::function<void(GameObject* triggerobject, GameObject* otherobject, TriggerAction action)> PhysicsCallback;
void GameObject::OnTrigger(GameObject* triggerobject, GameObject* otherobject, TriggerAction action)
{
if (m_OnTriggerCallback)
m_OnTriggerCallback(triggerobject, otherobject, action);
}
void GameObject::SetOnTriggerCallBack(PhysicsCallback callback)
{
m_OnTriggerCallback = callback;
}
Other class:
m_pSphere->SetOnTriggerCallBack(*pCbObj);
m_pSphere->OnTrigger(m_pWallLeft, m_pSphere, GameObject::TriggerAction(0));
I figured to use the OnTrigger() function I had to set m_OnTriggerCallback. When I tried to pass corresponding arguments however I got really stuck. It seems almost impossible to initalize PhysicsCallback without getting compiler errors.
I tried:
std::function<void(GameObject* triggerobject, GameObject* otherobject, GameObject::TriggerAction action)> *obj;
*obj = (m_pWallRight, m_pSphere, GameObject::TriggerAction(0));
But no luck. *obj doesn't accept any arguments. These following lines give the same errors:
GameObject::PhysicsCallback *pCbObj; = new GameObject::PhysicsCallback(new std::function<void()>()); //term does not evaluate to a function taking 3 arguments
GameObject::PhysicsCallback *pCbObj = new GameObject::PhysicsCallback((m_pWallRight, m_pSphere, GameObject::TriggerAction(0)));
And this line *pCbObj = GameObject::PhysicsCallback(m_pWallRight, m_pSphere, GameObject::TriggerAction(0));gives this intellisense error:
http://puu.sh/gi29n/95f0f7855b.png
I'm really confused, how to use the SetOnTriggerCallBack function?
Doing
m_pSphere->OnTrigger(m_pWallLeft, m_pSphere, GameObject::TriggerAction(0));
is actually calling GameObject::TriggerAction with 0 as argument. Then, it passes its result.
What is GameObject::TriggerAction? Is it a static method ? It should be because, otherwise, you have either to std::bind it to an object instance or to apply it directly.
With a lambda I was able to create an parameter that was acceptable for the compiler:
GameObject::PhysicsCallback trigger = [=](GameObject* triggerobject, GameObject* otherobject, GameObject::TriggerAction action){};
I did something to break the functionality in my program, but I can't figure out what. I define a typedef in a class headerfile:
typedef boost::function<void(instr_ptr, std::vector<ResultBase*>) > GenFunction;
And inside that class I have two instances:
GenFunction Gen;
GenFunction Kill
I set them as follows:
void DataFlowSolver::SetGenFunction(GenFunction &func)
{
Gen = func;
}
void DataFlowSolver::SetKillFunction(GenFunction &func)
{
Kill = func;
}
I have another function in a seperate header file:
void GenLiveVar(const instr_ptr instr, std::vector<ResultBase*> &list);
I create an instance of the DataFlowSolver class, and attempt to assign into it as follows:
blockSolver.SetGenFunction(GenLiveVar);
However, the compiler complains:
CFG.cc:617: error: no matching function for call to
'DataFlowSolver::SetGenFunction(void (&)(instr_ptr,
std::vector >&))'
DataFlowSolver.h:21: note: candidates are: void
DataFlowSolver::SetGenFunction(GenFunction&)
But it lets me do this:
GenFunction fun = GenLiveVar;
blockSolver.SetGenFunction(fun);
Anyone have an idea what might be wrong? I know this worked before, but I'm not sure how I managed to break it...
You are passing the boost::function into Set*Function by non-const reference. That prevents temporaries from being used as arguments, and the conversion from a normal function to a boost::function creates a temporary value. You will need to use a const reference for your parameter type for the code to work correctly.
Using C++.
pthread_t threads[STORAGE]; // 0-99
...
void run()
Error>>> int status = pthread_create(&threads[0], NULL, updateMessages, (void *) NULL);
if (status != 0)
{
printf("pthread_create returned error code %d\n", status);
exit(-1);
}
...
void ClientHandler::updateMessages(void *)
{
string reqUpdate = "91"; // Request for update
string recvMSG;
while (true)
{
sleep(5);
sending(sock,reqUpdate); // send
recvMSG = receiving(sock); // receive
QString output(recvMSG);
emit signal_chat(output, 0); // Print message to text box
}
}
...
Compile Error:
TCPClient.cpp:109: error: argument of type ‘void (ClientHandler::)(void*)’ does not match ‘void* (*)(void*)’
I can't figure out whats wrong.
Thanks in advance.
A pointer to a member function is different from a global function with the same signature since the member function needs an additional object on which it operates. Therefore pointers to these two types of functions are not compatible.
In this case this means that you cannot pass a member function pointer to pthread_create but only a pointer to a non-member (or static) function. A work around for this problem is to use the forth parameter of pthread_create to pass a pointer to a object to a global function which then calls the method of the passed object:
class ClientHandler {
public:
void updateMessages();
void run();
};
// Global function that will be the threads main function.
// It expects a pointer to a ClientHandler object.
extern "C"
void *CH_updateMessages(void *ch) {
// Call "real" main function
reinterpret_cast<ClientHandler*>(ch)->updateMessages();
return 0;
}
void ClientHandler::run() {
// Start thread and pass pointer to the current object
int status = pthread_create(&threads[0], NULL, CH_updateMessages, (void*)this);
...
}
It's nothing to do with threads, it's a normal C++ error, you're just passing an incompatible type of function pointer.
A function pointer is not the same as a member instance function pointer, even if their signature is the same; this is because there is an implicit reference to *this passed. You can't avoid this.
As pthread_create takes a free function, create a static function(is a free function) inside ClientHandler
static void Callback(void * this_pointer,int other_arg) {
ClientHandler* self = static_cast< ClientHandler*>(this_pointer);
self-> updateMessages(other_arg);
}
and call pthread_create as follows
pthread_create(&threads[0], NULL, &ClientHandler::Callback, (void *) pointer_to_ClientHandler,int other_arg);
That works because Callback is free function
YoLinux has a nice pthread tutorial that my help you in learning about threads.
As others have already said, the problem is that the signatures between the functions are different. Class member functions always have a "secret" extra parameter, the this pointer. So you can never pass a member function where a global function is expected. You can hack around this either with libraries such as Boost.Bind, or by making the function a static member of the class.
But the simplest, and most elegant solution is to use a different threading API.
Boost.Thread is a very nice threading library for C++ (pthreads is designed for C, and that's why it doesnt play well with C++ features such as class methods).
I'd recommend using that.
Your code could be rewritten as something like this:
class ClientHandler {
public:
ClientHandler(/* All the parameters you want to pass to the thread. Unlike pthreads you have complete type safety and can pass as many parameters to this constructor as you like */){...}
void operator()() // boost.thread calls operator() to run the thread, with no parameters. (Since all parameters were passed in the constructor and saved as member variables
{
string reqUpdate = "91"; // Request for update
string recvMSG;
while (true)
{
sleep(5);
sending(sock,reqUpdate); // send
recvMSG = receiving(sock); // receive
QString output(recvMSG);
emit signal_chat(output, 0); // Print message to text box
}
}
// whatever arguments you want to pass to the thread can be stored here as member variables
};
boost::threead_group gr; // can store all your threads here, rather than being limited to your fixed-size array
gr.create_thread(ClientHandler(/* construct a ClientHandler object with the parameters you like*/));
You're passing a member function instead of a global, normal, one.
Just define:
void updateMessages(void *) {
static ClientHandler c;
// use c..
}