Create sigc::slot with no arguments - c++

I'm trying to connect a timeout handler to my gtkmm code as shown in gtkmm book. However, my particular on_timeout() function doesn't need any arguments, and I'm struggling to properly create a sigc::slot object to pass to the connect function, as I encounter the following error (among others):
error: no matching function for call to ‘bind(sigc::bound_mem_functor0<bool, DerivedWindow>)
and several
candidate expects 2 arguments, 1 provided
referring to sigc::bind. How I am calling both functions:
_timeout_slot = sigc::bind(sigc::mem_fun(*this,&DerivedWindow::on_timeout));
_connection = Glib::signal_timeout().connect(_timeout_slot,timeout_value);
I'm doing this on a class DerivedWindow derived from Gtk::Window. What exactly am I doing wrong? Do I need to use sigc::bind and sigc::mem_func if I don't require any arguments?

You don't need sigc::bind here since you are not binding any additional arguments to the slot (dealing with dereferencing the member function pointer for this is already taken care of by sigc::mem_fun). So, this is sufficient:
_timeout_slot = sigc::mem_fun(*this, &MyWindow::on_timeout)
_connection = Glib::signal_timeout().connect(_timeout_slot, timeout_value);
A quick tip: if you can use C++11, you can just pass lambdas as arguments to connect, which makes things more readable:
_connection = Glib::signal_timeout().connect([this]{ return on_timeout(); }, timeout_value);
For this to work, you may need to add
namespace sigc{
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
}
Also, if you want to connect to signals of a class instance (say a Gtk::Button* btn), you can make things even more compact by defining a macro
#define CONNECT(src, signal, ...) (src)->signal_##signal().connect(__VA_ARGS__)
which then allows you to write
CONNECT(btn, clicked, [this]{ btn_clicked_slot(); });

Related

ROS2 Dynamic messages template

I have a question regarding ROS2 messages or possibly just standard C++, maybe one of you have tried something similar before, or can tell me that what I am trying to accomplish won't work.
What I'm trying to create is a library that I can use to quickly create a ROS2 Node, dynamically add publishers and/or subscribers, depending on the situation, before starting the node.
The problem I'm facing is that ROS2 uses message types like std_msgs::msg::String. Example source can be found on github.
The source uses the following code to create a subscriber:
subscription_ = this->create_subscription<std_msgs::msg::String>("topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
I would like to create a function that can create a subscriber using a given message type i.e.:
void createListener(std::string topicName, 'messagetype')
{
auto subscription_ = this->create_subscription<'messagetype'>(topicname, 10, [this]{}, this, _1));
//adding the created subscriber to a list is already done
}
This would allow me to use the same function while still being able to use different messages like:
nav_msgs::msg::Path
geometry_msgs::msg::Point
without having to create a new function for every message type.
I can't seem to find the template type that is used in the create_subscribtion<>() function, all I can find is that each message creates its own type.
std_msgs::msg::String would return the std_msgs::msg::String_<std::allocator<void>> type.
Is there a way that i can make this work?
You could use templates here right, by doing the following:
template <typename MsgType>
void createListener(std::string topicName)
{
auto subscription_ = this->create_subscription<MsgType>(topicname, 10, [this]{}, this, _1));
//adding the created subscriber to a list is already done
}
This function can then be called, for example by:
createListener<nav_msgs::msg::Path>("topicName")

Error invalid use of void expression. Trying to pass a parameter through to the function

I am trying to initialize a server to look as specific inputs based on the request it gets. there are a lot of them so I want to initialize it with a loop as follows:
void serverInit() {
for (int i = 1; i <= qty; i++) {
String s = "/readBatt" + i;
server.on(s, runTest(i));
}
server.begin();
Serial.println("Server started.");
}
It's telling me that server.on(s, runTest(i)); is an invalid use of void expression. I know it wants it formatted as server.on(s, runTest) but the function runTest(int n) takes a parameter. How can i pass this parameter through to the function?
It seems you are using the WebServer class from the ESP32 Arduino libraries. As you have gleaned already, the callback specified in the on() method does not accept any arguments.
You have an alternative, however. You can specify a 'placeholder' in the URL path - using curly brackets - {}. In the callback, then, the corresponding argument can be retrieved by using the pathArg() method - which accepts the argument index as parameter.
Example ...
You could define your API endpoint as /readBatt/<battery number>. To configure the server to handle requests to this endpoint, then, you would use something like
#include <uri/UriBraces.h>
server.on(UriBraces("/readBatt/{}"), runTest);
In your callback, you would retrieve the first argument as follows ...
static void runTest() {
String batteryNumber = server.pathArg(0);
Serial.println("Request to read battery");
String response = "You attempted to read battery " + batteryNumber;
response += ".\nThis endpoint is a placeholder. Check again soon!";
server.send(200, "text/plain", response);
}
Finally ... Suppose your ESP8266 was running on local IP address 192.168.1.9. You could access your new API endpoint by opening
http://192.168.1.9/readBatt/1
in your browser. (Replace 1 with the relevant battery number.)
I don't think there are versions of the pathArg() which return an integer, unfortunately, so you may have to perform a conversion at some point.
You can use what's called a "closure". A closure lets you compose a function which retains access to variables outside of its scope.
A closure is written using a "lambda expression" - basically an anonymous function. C++'s syntax for lambda expressions looks like this:
[capture variable list](argument list) { body}
The capture variable list is a list of variables you want to be made available inside the body. The argument list is the normal function argument list that would get passed in by the caller. You'd write the lambda expression you need like this:
[i]() { runTest(i); }
and use it like this:
server.on(s, [i]() { runTest(i); });
To be clear, #David Collins' answer is the better way to write the web server. Using a parameter in the URL is better than creating several URLs with the parameter embedded in them. I'm just answering the question of how to pass a parameter to a function that gets called without arguments. If you write the web server code the better way, you won't need to do this (although I would do a bounds check on the value passed in the URL to make sure you're getting a valid battery number).

ROS subscribe callback - using boost::bind with member functions

I'm trying to subscribe to different topics in ROS (one for every vehicle that pops up) using the same callback for all of them. The idea is that boost::bind will pass the topic name as an additional argument so I know which vehicle I should access in the callback.
The problem is that, even though I've gone through multiple questions on the topic, none of the solutions seem to work.
Basically, I have the following class VOBase containing a std::map<std::string, VOAgent*> agents_ with a member function as follows:
void VOBase::callback_agentState(const custom_msgs::VState::ConstPtr& vStateMsg,
std::string topic) {
// [...] regex to find agent name from topic string
std::string agent_name = match.str();
// [...] Check if agent name exists, else throw exception
// Process message
agents_[agent_name]->pos_ = vStateMsg->pose.position; // etc.
}
Which I'm calling through this subscription:
void VOBase::callback_agentList(const custom_msgs::VehicleList& vehListMsg) {
// [...] New agent/vehicle found: process vehListMsg and get agent_name string
// Subscribe to VState
topic_name = agent_name + "/state_estimate";
subscribers_[topic_name] = nodeHandlePtr->subscribe<custom_msgs::VState>(topic_name, 1,
std::bind(&VOBase::callback_agentState, this, _1, topic_name));
}
However, I'm getting a template argument deduction/substitution failed with all the candidates and this error:
mismatched types ‘std::reference_wrapper<_Tp>’ and ‘VO::VOBase*’
typename add_cv<_Functor>::type&>::type>()(
I've tested a number of the solutions out there, e.g. using std::ref(this) to get a std::reference_wrapper<_Tp> instead of a VO::VOBase* (the reference doesn't survive though: use of deleted function), using boost::bind instead of std::bind (but it should be all the same since C++11), with and without the ...::ConstPtr for the ROS message in the callback function arguments (and in the subscribe<acl_msgs::ViconState::ConstPtr>, etc. So I'm just juggling with partial solutions and their permutations here...
Any clues?
I haven't looked into the specifics of the code you show (it's hard to figure out the information not shown and deduce what's required).
However, last time I helped someone with ROS subscriptions and the type-deduction, it was apparent that the handler should take a shared_ptr to the message. This might help you get started seeing a solution:
Error using boost::bind for subscribe callback

Submitting concurrent task via QFuture from GUI thread

In order to avoid computations in GUI thread on button click I'm trying to run it in separate thread.
As soon as I want to have ability to monitor progress my code is based on this source.
So, my code is:
futureWatcher.setFuture(QtConcurrent::mapped(library_pool.cbegin(), library_pool.cend(), util->loadFilesInLibrary(library_pool)));
futureWatcher.waitForFinished();
table = QFuture::result();
Which is quite similar to the given sorce from qt docs, but it gives corresponding errors:
C2893: Failed to specialize function template 'QFuture<QtPrivate::MapResultType<void,MapFunctor>::ResultType> QtConcurrent::mapped(Iterator,Iterator,MapFunctor)'
C2780: 'QFuture<QtPrivate::MapResultType<void,MapFunctor>::ResultType> QtConcurrent::mapped(const Sequence &,MapFunctor)': expects 2 arguments - 3 provided
C2955: 'QFuture': use of class template requires template argument list
'QFuture<T>::result': illegal call of non-static member function
So, how do I properly populate worker thread(s) with function from non-gui class in button_clicked slot without making GUI hand?
UPD
Well, I've succeeded with compiling code for now and this is how it works:
futureWatcher.setFuture(QtConcurrent::run(&this->util, &Utils::loadFilesInLibrary, library_pool.at(0)));
futureWatcher.waitForFinished();
library_pool = future.result();
But button click still results to error in runtime:
My function which I'm trying to run generates no widgets, so the reason of this message is unclear.
I've read couple questions (like this) where all the code stated to work but it resides only in main() which is far from my needs. So, again, how do I start it from GUI thread?
You can use non-static members with QtConcurrent methods with the help of a wrapper. There is more discussion about it at Qt's Forums. Here's another similar question asking about how to use the wrapper.
struct AddWrapper {
Utils *utils = nullptr;
typedef MyType result_type;
AddWrapper(Util *u): instance(u) {};
MyType operator()(const MyType &t) const {
return instance->longMethod(t);
}
}
Utils *foo = new Utils();
AddWrapper wrapper(foo);
QFuture<MyType> results = QtConcurrent::mapped(myList, wrapper);

ColdFusion function variable name and CfBuilder

I need to call a function of an object and pass it a variable. Because I need to make multiple call to function of this object I've tried to make one only handler that invoke the specific function by the form value I pass it. The code works, but CFBuilder show me that there is an error (missing semicolon on the last row). I'm on Railo.
local.myReport = seoUtility.init();
local.func = form.action;
local.report = local.myReport[local.func](form.user);
So the question is: this code is correct? I could simply ignore the cfbuilder error icon?
If you don't want CFBuilder to nag you about the syntax, you can change to this:
local.myReport = seoUtility.init();
local.func = local.myReport[form.action];
local.myReport.func = local.func;
local.report = local.myReport.func(form.user);
This sets local.func to the instance of seoUtility as a reference to the actual function you want to call, preserving its relationship to the parent object. This way the offending []() syntax isn't needed.
However, this only works if seoUtility.init() is returning a fresh instance every time, as opposed to a singleton shared by the application, in which case there would be a race condition on all calls to local.myReport.func().