We're getting this compile error followed by many more errors showing attempts to match the subscribe parameters to all possible candidate functions when using boost::bind as a callback for subscribe.
error: no matching function for call to ‘ros::NodeHandle::subscribe(const char [18], int, boost::_bi::bind_t<void, void (*)(const geometry_msgs::WrenchStamped_<std::allocator<void> >&, moveit::planning_interface::MoveGroup&), boost::_bi::list2<boost::arg<1>, boost::_bi::value<moveit::planning_interface::MoveGroup*> > >)’
Our code is as follows. The commented lines show the code which works when the MoveGroup context (object pointer) is not passed.
#include <stdio.h>
#include <boost/bind.hpp>
#include <geometry_msgs/WrenchStamped.h>
#include <moveit/move_group_interface/move_group.h>
using namespace Eigen;
using namespace std;
//void contact_callback(const geometry_msgs::WrenchStamped& msg) {
void contact_callback(const geometry_msgs::WrenchStamped& msg, moveit::planning_interface::MoveGroup &group){
//if(msg.wrench.force.z > 5) group.stop();
}
int main(int argc, char **argv) {
ros::init(argc, argv, "get_stiffness");
ros::NodeHandle node_handle;
ros::AsyncSpinner spinner(1);
spinner.start();
moveit::planning_interface::MoveGroup group("manipulator");
ros::Subscriber contact_sub;
//contact_sub = node_handle.subscribe("/finger1/nano17ft",1,contact_callback);
contact_sub = node_handle.subscribe("/finger1/nano17ft",100,boost::bind(contact_callback,_1,&group));
ros::waitForShutdown();
return 0;
}
The handler takes a MoveGroup& but you pass it the address of group.
Instead use ref(group):
boost::bind(contact_callback,_1,boost::ref(group))
Or, indeed
std::bind(contact_callback,std::placeholders::_1,std::ref(group))
UPDATE:
Your callback does not adhere to the required signature:
void contact_callback(const geometry_msgs::WrenchStamped&, moveit::planning_interface::MoveGroup & group) {
must be
void contact_callback(const boost::shared_ptr<geometry_msgs::WrenchStamped const>, moveit::planning_interface::MoveGroup & group) {
At the call site you must either make the message type explicit (it's in non-deducible context):
contact_sub = node_handle.subscribe<geometry_msgs::WrenchStamped>("/finger1/nano17ft", 100,
boost::bind(contact_callback, _1, boost::ref(group)));
OR you could simply explicitly wrap in a function<> first:
boost::function<void(const boost::shared_ptr<geometry_msgs::WrenchStamped const>&)> callback =
boost::bind(contact_callback, _1, boost::ref(group));
contact_sub = node_handle.subscribe("/finger1/nano17ft", 100, callback);
Live Demo
With all roscpp/Eigen stuff stubbed out:
Live On Coliru
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <iostream>
////////////////// STUBS STUBS STUBS //////
//#include <geometry_msgs/WrenchStamped.h>
namespace Eigen {}
namespace geometry_msgs {
struct WrenchStamped {}; }
namespace moveit { namespace planning_interface { struct MoveGroup { std::string name; MoveGroup(std::string s):name(s){} }; } }
namespace ros {
void init(...) {}
void waitForShutdown(...) {}
struct Subscriber {};
struct NodeHandle {
using VoidConstPtr = void const *;
enum class TransportHints {};
template <typename M>
Subscriber subscribe(const std::string &topic, uint32_t queue_size,
const boost::function<void(const boost::shared_ptr<M const> &)> &callback,
const VoidConstPtr &tracked_object = VoidConstPtr(),
const TransportHints &transport_hints = TransportHints())
{
(void)topic, (void)queue_size, void(tracked_object), void(transport_hints);
callback({});
return {};
}
};
struct AsyncSpinner {
AsyncSpinner(int) {}
void start() {}
};
};
//#include <moveit/move_group_interface/move_group.h>
////////////////// END STUBS END STUBS END STUBS //////
using namespace Eigen;
void contact_callback(const boost::shared_ptr<geometry_msgs::WrenchStamped const>, moveit::planning_interface::MoveGroup & group) {
// if(msg.wrench.force.z > 5) group.stop();
std::cout << "Invoked! " << group.name << "\n";
}
int main(int argc, char **argv) {
ros::init(argc, argv, "get_stiffness");
ros::NodeHandle node_handle;
ros::AsyncSpinner spinner(1);
spinner.start();
moveit::planning_interface::MoveGroup group("manipulator");
ros::Subscriber contact_sub;
contact_sub = node_handle.subscribe<geometry_msgs::WrenchStamped>("/finger1/nano17ft", 100,
boost::bind(contact_callback, _1, boost::ref(group)));
{
boost::function<void(const boost::shared_ptr<geometry_msgs::WrenchStamped const>&)> callback =
boost::bind(contact_callback, _1, boost::ref(group));
contact_sub = node_handle.subscribe("/finger1/nano17ft", 100, callback);
}
ros::waitForShutdown();
}
Prints
Invoked! manipulator
Invoked! manipulator
Related
I've running Mosquitto on my RPI4. But right know I only can set static callback functions. Is there a way to use class members?
I've tried to use std::bind to pass a class member function as callback:
main.cpp
#include <stdio.h>
#include <mosquitto.h>
#include "mqtt.h"
#include <string>
int main(int argc, char **argv)
{
MqttConnector * mqtt = new MqttConnector("piClient", "send", "rc", 1883, "localhost", 60);
mqtt->startClient();
return 0;
}
mqtt.h (only important parts
#include <mosquitto.h>
#include <string>
#include <stdio.h>
class MqttConnector
{
public:
MqttConnector(std::string id,
std::string sendTopic,
std::string receiveTopic,
int port,
std::string host,
int keepalive);
~MqttConnector();
void startClient();
private:
void messageCallback(struct mosquitto *mosq,
void *userdata,
const struct mosquitto_message *message);
struct mosquitto *mosqClient = NULL;
int keepalive;
int port;
std::string id;
std::string host;
std::string sendTopic;
std::string receiveTopic;
};
mqtt.cpp
#include "mqtt.h"
#include <stdio.h>
#include <string>
#include <string.h>
#include <mosquitto.h>
#include <functional>
using namespace std::placeholders;
MqttConnector::MqttConnector(std::string id, std::string sendTopic, std::string receiveTopic, int port, std::string host, int keepalive)
{
mosquitto_lib_init();
mosqClient = mosquitto_new(NULL, true, NULL);
if(!mosqClient){
fprintf(stderr, "Error: Out of memory.\n");
}
this->keepalive = keepalive;
this->id = id;
this->host = host;
this->port = port;
this->sendTopic = sendTopic;
this->receiveTopic = receiveTopic;
}
MqttConnector::~MqttConnector()
{
mosquitto_destroy(mosqClient);
mosquitto_lib_cleanup();
}
void MqttConnector::messageCallback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
// I want to access class members like sendTopic / receiveTopic here
}
void MqttConnector::startClient()
{
// try to bind class members function
mosquitto_message_callback_set(mosqClient, std::bind(&MqttConnector::messageCallback, this, _1, _2, _3));
//other stuff
}
This gives me the following error while compiling:
cannot convert 'std::_Bind_helper<false, void (MqttConnector::*)(mosquitto*, void*, const mosquitto_message*), MqttConnector*, const std::_Placeholder<1>&, const std::_Placeholder<2>&, const std::_Placeholder<3>&>::type' {aka 'std::_Bind<void (MqttConnector::*(MqttConnector*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(mosquitto*, void*, const mosquitto_message*)>'} to 'void (*)(mosquitto*, void*, const mosquitto_message*)'
83 | mosquitto_message_callback_set(mosqClient, std::bind(&MqttConnector::messageCallback, this, _1, _2, _3));
Why doesn't it work?
Thanks!
This is a problem of using C-api from C++. What is the difference between a member function and a free function? When you provide a pointer to a member function a pointer to the class object is implicitly passed as the first parameter. Since C-api doesn't do that, but the problem is well known, the solution was introduced and it is called passing a context. Usually it is done through a void pointer. Functions that register callbacks usually take the pointer to the free function and a pointer to context. Then this pointer will be passed as one of the callback parameters.
In mosquitto case this context pointer is passed beforehand at the creation of a mosquitto object with mosquitto_new.
In order to make the callback function behave like a C function, we declare it static.
Inside the callback function we use static_cast to cast the void pointer to the object that we have provided.
mqtt.h
#include <mosquitto.h>
#include <string>
#include <stdio.h>
class MqttConnector
{
public:
MqttConnector(std::string id,
std::string sendTopic,
std::string receiveTopic,
int port,
std::string host,
int keepalive);
~MqttConnector();
void startClient();
private:
// make this function static
---->
static void messageCallback(struct mosquitto *mosq,
void *userdata,
const struct mosquitto_message *message);
struct mosquitto *mosqClient = NULL;
int keepalive;
int port;
std::string id;
std::string host;
std::string sendTopic;
std::string receiveTopic;
};
mqtt.cpp
#include "mqtt.h"
#include <stdio.h>
#include <string>
#include <string.h>
#include <mosquitto.h>
#include <functional>
using namespace std::placeholders;
MqttConnector::MqttConnector(std::string id, std::string sendTopic, std::string receiveTopic, int port, std::string host, int keepalive)
{
mosquitto_lib_init();
// provide apointer to this as user data
mosqClient = mosquitto_new(NULL, true, this);
---->
if(!mosqClient){
fprintf(stderr, "Error: Out of memory.\n");
}
this->keepalive = keepalive;
this->id = id;
this->host = host;
this->port = port;
this->sendTopic = sendTopic;
this->receiveTopic = receiveTopic;
}
MqttConnector::~MqttConnector()
{
mosquitto_destroy(mosqClient);
mosquitto_lib_cleanup();
}
void MqttConnector::messageCallback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
// Use static cast to get pointer to your class object from userdata
MqttConnector *connector = static_cast<MqttConnector>(userdata);
connector->sendTopic;
}
void MqttConnector::startClient()
{
// static callback
mosquitto_message_callback_set(mosqClient, &MqttConnector::messageCallback);
// lambda callback
// beware, you can't use capture here
mosquitto_message_callback_set(&m, [/*no capture possible*/] (struct mosquitto *, void *userdata, const struct mosquitto_message *)
{
MqttConnector *connector = static_cast<MqttConnector>(userdata);
connector->sendTopic;
});
}
I'm trying to create a class that stores pointers to member functions of other classes and that can be executed from a text command (like a game console).
I did something functional, based on an example found here, that stores members with string-like input. Below is my implementation.
file: Command.hpp
#include <string>
#include <functional>
#include <unordered_map>
#include <string>
#include <iostream>
using namespace std;
class Command
{
public:
Command();
virtual ~Command();
void RegisterCommand(string command, function<void(const string&)> fun);
void Run(const string& command, const string& arg);
private:
unordered_map<string, function<void(const string&)>> functions;
};
file: Command.cpp
Command::Command()
{
}
Command::~Command()
{
}
void Command::RegisterCommand(string command, function<void(const string&)> fun)
{
functions[command] = fun;
}
void Command::Run(const string& command, const string& arg)
{
functions[command](arg);
}
file: main.cpp
#include "Command.hpp"
// function to register
void xyz_fun(const string& commandLine)
{
cout << "console output: " << commandLine << endl;
}
int main(int argc, char* argv[])
{
Command m_Cmd;
// Register function
m_Cmd.RegisterCommand("xyz_fun", xyz_fun);
// Run registered function
m_Cmd.Run("xyz_fun", "hello world.");
return EXIT_SUCCESS;
}
My question is how to implement a generic class to store members with unknown input arguments (Booleans, integers, doubles, strings, etc.).
For example, I could do:
m_Cmd.RegisterCommand("xyz_fun2", xyz_function2);
and call
m_Cmd.Run("xyz_fun2", false)
which has a boolean argument instead of a string.
Thanks in advance for your attention and any help is welcome.
Instead of
unordered_map<string, function<void(const string&)>> functions;
you could do
union acceptable_types { int i; char c; bool b; std::string* s; ... };
unordered_map<string, function<void(acceptable_types)>> functions;
Then when calling functions, just place the value wanted by the function into a variable of type acceptable_types.
If a function is wants to use a specific value, it should just use a specific member of the acceptable_types union.
Here's an example:
#include "Command.hpp"
void
my_bool_func (acceptable_types union_param)
{
bool bool_var = union_param.b;
// ...
// Use bool_var
// ...
}
void
my_string_func (acceptable_types union_param)
{
std::string string_var = *(union_param.s);
// ...
// Use string_var
// ...
}
int
main(int argc, char* argv[])
{
Command my_command;
acceptable_types union_var;
my_command.RegisterCommand("my_bool_func", my_bool_func);
my_command.RegisterCommand("my_string_func", my_string_func);
union_var.b = true;
my_command.Run("my_bool_func", union_var);
*(union_var.s) = "hello world.";
my_command.Run("my_string_func", union_var);
return 0;
}
I want to connect a callback function to a boost signal through a public function. I can pass a function pointer just fine, but if I try to use std::bind to pass a member function, it will not compile. Giving me error saying no viable conversion. What type should I use for the App::SetCallback function argument?
#include <functional>
#include <boost/signal.hpp>
using namespace std::placeholders; // for _1, _2, _3...
//plain simple call back function
void SimpleCallback(int value) {
//do nothing
}
//class contains a boost::signal, set callback through a public function
class App {
public:
App() : sig_()
{}
typedef boost::signal<void (int value)> SigType;
typedef std::function<void (int value)> CallbackFunType;
//connect signal to a callback function
void SetCallback(CallbackFunType callback) {
sig_.connect(callback);
}
//private: //comment this out for testing purpose.
SigType sig_; //this is the boost::signal
};
//class that has member callback function
class MyCallback {
public:
MyCallback():
val(0), app()
{}
void MemberCb(int value){
val = value;
}
void Connect() {
auto bind_fun = std::bind(&MyCallback::MemberCb, this, _1);
app.SetCallback(bind_fun); //this will not compile, no viable conversion
app.sig_.connect(bind_fun); //this is fine
app.SetCallback(SimpleCallback); //this is fine
}
private:
int val;
App app;
};
int main(int argc, char **argv) {
MyCallback my_cb;
my_cb.Connect();
return 1;
}
----------------UPDATE-----------------
Reading boost signal documentation more carefully, I learned that I can pass slot type. This solves my problem
#include <functional>
#include <boost/signal.hpp>
using namespace std::placeholders; // for _1, _2, _3...
//plain simple call back function
void SimpleCallback(int value) {
//do nothing
}
//class contains a boost::signal, set callback through a public function
class App {
public:
App() : sig_()
{}
typedef boost::signal<void (int value)> SigType;
typedef SigType::slot_type CallbackFunType;
//typedef std::function<void (int value)> CallbackFunType;
//connect signal to a callback function
void SetCallback(CallbackFunType callback) {
sig_.connect(callback);
}
//private: //comment this out for testing purpose.
SigType sig_; //this is the boost::signal
};
//class that has member callback function
class MyCallback {
public:
MyCallback():
val(0), app()
{}
void MemberCb(int value){
val = value;
}
void Connect() {
auto bind_fun = std::bind(&MyCallback::MemberCb, this, _1);
app.SetCallback(bind_fun); //using SigType::slot_type
app.sig_.connect(bind_fun);
app.SetCallback(SimpleCallback);
}
private:
int val;
App app;
};
int main(int argc, char **argv) {
MyCallback my_cb;
my_cb.Connect();
return 1;
}
Reading boost signal documentation more carefully, I learned that I can pass slot type. This solves my problem
#include <functional>
#include <boost/signal.hpp>
using namespace std::placeholders; // for _1, _2, _3...
//plain simple call back function
void SimpleCallback(int value) {
//do nothing
}
//class contains a boost::signal, set callback through a public function
class App {
public:
App() : sig_()
{}
typedef boost::signal<void (int value)> SigType;
typedef SigType::slot_type CallbackFunType;
//typedef std::function<void (int value)> CallbackFunType;
//connect signal to a callback function
void SetCallback(CallbackFunType callback) {
sig_.connect(callback);
}
//private: //comment this out for testing purpose.
SigType sig_; //this is the boost::signal
};
//class that has member callback function
class MyCallback {
public:
MyCallback():
val(0), app()
{}
void MemberCb(int value){
val = value;
}
void Connect() {
auto bind_fun = std::bind(&MyCallback::MemberCb, this, _1);
app.SetCallback(bind_fun); //using SigType::slot_type
app.sig_.connect(bind_fun);
app.SetCallback(SimpleCallback);
}
private:
int val;
App app;
};
int main(int argc, char **argv) {
MyCallback my_cb;
my_cb.Connect();
return 1;
}
I'm trying to save the result of bind to std:function, then pass it as parameter to another function, and store it as data member. Then I use asio async_wait, but when i return from the wait, and try to operate the function i saved i get segmentation fault. any Idea why?
#include <memory>
#include <iostream>
#include <asio/io_service.hpp>
#include <functional>
#include <asio/deadline_timer.hpp>
using namespace std;
typedef std::function<void (const std::error_code& error)> TM_callback;
class Timer {
public:
Timer(asio::io_service& io_service) :_timer(io_service) {}
void start(TM_callback cb) {
_cb = cb;
_timer.expires_from_now(boost::posix_time::milliseconds(1000));
TM_callback timeoutFunc = std::bind(&Timer::onTimeout, this, std::placeholders::_1);
_timer.async_wait(timeoutFunc);
}
private:
void onTimeout(const std::error_code& error) {
(_cb)(error); // <-- here i get segmentation fault
}
TM_callback _cb;
asio::deadline_timer _timer;
};
class COL {
public:
COL(asio::io_service& io_service): _inTimer(io_service){}
void startInTimer() {
TM_callback cb = std::bind(&COL::onInTimeout, this, std::placeholders::_1);
_inTimer.start(cb);
}
private:
void onInTimeout(const std::error_code& error) {cout<<error.message();}
Timer _inTimer;
};
int main()
{
asio::io_service io_service;
COL col(io_service);
col.startInTimer();
return 0;
}
Ok, the most likely problem is in the code you don't show. As you can see #m.s. didn't "imagine" your problem. He forgot the io_service::run() too:
int main() {
asio::io_service io_service;
COL col(io_service);
col.startInTimer();
io_service.run();
}
Still no problem. Live On Coliru
The problem starts when inTimer is not guaranteed to live until the completion handler is executed:
int main() {
asio::io_service io_service;
{
COL col(io_service);
col.startInTimer();
}
io_service.run();
}
Now you have Undefined Behaviour: Live On Coliru
Solution
The easiest solution is to make the COL (what is that?) object live long enough. The more structural/idiomatic way would to let the bind keep the Timer object alive, e.g. using a shared_ptr:
Live On Coliru
#include <iostream>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp>
#include <boost/asio.hpp>
using namespace std;
typedef std::function<void(const boost::system::error_code &error)> TM_callback;
namespace asio = boost::asio;
class Timer : public boost::enable_shared_from_this<Timer> {
public:
Timer(asio::io_service &io_service) : _timer(io_service) {}
void start(TM_callback cb) {
_cb = cb;
_timer.expires_from_now(boost::posix_time::milliseconds(1000));
TM_callback timeoutFunc = boost::bind(&Timer::onTimeout, shared_from_this(), boost::asio::placeholders::error);
_timer.async_wait(timeoutFunc);
}
private:
void onTimeout(const boost::system::error_code &error) {
(_cb)(error);
}
TM_callback _cb;
asio::deadline_timer _timer;
};
class COL : public boost::enable_shared_from_this<COL> {
public:
COL(asio::io_service &io_service) : _svc(io_service) {}
void startInTimer() {
TM_callback cb = boost::bind(&COL::onInTimeout, shared_from_this(), boost::asio::placeholders::error);
boost::shared_ptr<Timer> _inTimer = boost::make_shared<Timer>(_svc);
_inTimer->start(cb);
}
private:
void onInTimeout(const boost::system::error_code &error) { cout << error.message(); }
asio::io_service& _svc;
};
int main() {
asio::io_service io_service;
{
boost::make_shared<COL>(io_service)->startInTimer();
}
io_service.run();
}
Note that this subtly also fixes the problem that more than one timer couldn't be in flight at a give time (scheduling a new timer would cancel the pending one).
I would like to create a simple class to signals handling (just for study) with std::bind. However, I could not compile this code:
#include <iostream>
#include <functional>
#include <csignal>
using namespace std;
class SignalHandler
{
public:
void handler(int value)
{
cout << value << endl;
}
SignalHandler()
{
auto callback = std::bind(&SignalHandler::handler, this, std::placeholders::_1);
sighandler_t ret = std::signal(SIGTERM, callback);
if (SIG_ERR == ret) {
throw;
}
}
};
int main() {
SignalHandler handler;
raise(SIGTERM);
return 0;
}
(GCC) Compiler exit:
prog.cpp: In constructor 'SignalHandler::SignalHandler()':
prog.cpp:21:51: error: cannot convert 'std::_Bind(SignalHandler*, std::_Placeholder<1>)>' to '__sighandler_t {aka void ()(int)}' for argument '2' to 'void ( signal(int, __sighandler_t))(int)'
sighandler_t ret = std::signal(SIGTERM, callback);
You can use static methods to handle SIGTERM, et al. I've done that before. static was the key to get signatures to match.