Lambda expressions in thread pool in C++ - c++

I am trying to push a bunch of lambda expressions on a thread pool in C++. I know there are no in-built thread pool implementations in C++ (or at least that is what I read so far), so I used the one I found at: https://github.com/vit-vit/ctpl (I found it through this stackoverflow answer). I managed to use it when I had lambda expressions which would return basic C++ types (int, double, etc), but I cannot get it to work when I have a lambda expression which returns a custom class instance. I made a simple example to illustrate my problem, using this dummy class Person.
This is the dummy class Person:
class Person {
private:
std::string name;
int age;
public:
Person(std::string name, int age) : name(std::move(name)), age(age) {}
std::string getName() const { return name; }
int getAge() const { return age; }
};
And I have this function in my main file which just creates an instance of the Person class:
Person generatePersonInstance(std::string name, int age) {
return Person(std::move(name), age);
}
And then I just try to use the thread pool (again, the one I found at https://github.com/vit-vit/ctpl) with a lambda expression which returns a Person instance:
#include "ctpl_stl.h"
#include "Person.h"
int main() {
std::string myName = "myName";
int myAge = 100;
ctpl::thread_pool pool(4);
std::future<Person> f = pool.push([&myName, &myAge]{ generatePersonInstance(myName, myAge); });
return 0;
}
As you can see, I am trying to push on the thread pool a lambda expression which will just return a Person instance with the given parameters. The idea is that after this code runs, I can run f.get() to get the Person instance itself from the std::future<Person> instance. But my problem is that this code does not run, and I don't know why. At the pool.push part I get the error:
No matching member function for call to 'push' candidate template
ignored: substitution failure [with F = (lambda at
D:<my_path>\main.cpp:146:39), Rest = <>]: no matching function for
call to object of type '(lambda at D:<my_path>\main... candidate
template ignored: substitution failure [with F = (lambda at
D:<my_path>\main.cpp:146:39)]: no matching function for call to
object of type '(lambda at D:<my_path>\main.cpp:146:39)'
How can I fix this and make the code work as I intended?

I see 2 issues:
You're missing a return of Person in the lambda.
It looks like the argument of ctpl::push must accept an int thread ID.
std::future<Person> f = pool.push([&myName, &myAge](int id) {
return generatePersonInstance(myName, myAge);
});

Related

Question regarding the use of std::bind in ROS2 tutorial

I am fairly new to C++ and I have a question regarding practices of std::bind. The following snippet is copied from this tutorial on the ROS2 website. The code creates a class where the timer_ field hosts a timer that is created using create_wall_timer(). creates_wall_timer() accepts a callback object of type CallbackT &&. In the constructor of the class, why does the author pass the result of std::bind(...) as the callback to create_timer() instead of a direct pointer or reference to the timer_callback method?
Apologies for the long questions. I am not really good at asking these questions. Hopefully, I didn't miss too much information that you need.
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
/* This example creates a subclass of Node and uses std::bind() to register a
* member function as a callback from the timer. */
class MinimalPublisher : public rclcpp::Node
{
public:
MinimalPublisher()
: Node("minimal_publisher"), count_(0)
{
publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
timer_ = this->create_wall_timer(
500ms, std::bind(&MinimalPublisher::timer_callback, this));
}
private:
void timer_callback()
{
auto message = std_msgs::msg::String();
message.data = "Hello, world! " + std::to_string(count_++);
RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
publisher_->publish(message);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
size_t count_;
};
You can't pass a pointer to a member function in isolation (unless that function is declared static), because it needs an instance of the [right kind of] object to be called on.
std::bind binds a pointer to an object (this, in this example) to the member function pointer (&MinimalPublisher::timer_callback) so that when the time comes to call the function, there is an instance of the required / desired object available.
To look at this from another (simpler) angle, consider what happens if you write:
MinimalPublisher::timer_callback ();
If MinimalPublisher::timer_callback is not a static function the compiler will complain, because a non-static function can only be called through a [pointer to a] MinimalPublisher object, so something like:
my_minimal_publisher_object.MinimalPublisher::timer_callback ();
or:
my_minimal_publisher_object_pointer->MinimalPublisher::timer_callback ();
You might like to experiment with this in your favourite online compiler.
Incidentally, std::bind has been largely superseded by capturing lambdas these days. So, in order to capture the required object instance (and taking my original example over at Wandbox as a starting point), you might do:
#include <functional>
struct MyStruct
{
void foo ();
};
int main()
{
MyStruct s;
std::function <void ()> f = [&s] { s.foo (); };
// Do things with f
}

Factory pattern and std::bind methods

I've implemented a factory pattern in C++ some weeks ago using the following guide : https://www.codeproject.com/Articles/363338/Factory-Pattern-in-Cplusplus
Since then it worked well: all of the methods used in the factory pattern were returning the same type, and were also taking the same arguments types, until today. I now need to add bind new arguments to the methods I use, so methods signatures are not the same anymore.
I am currentyl using 2 things, and implementing a third one :
1) Actions: each represented as a class and containing a static AAction::ptr create(void* buff) method. Actions inherits from AAction class. Actions can be serialized using their own serialize() internal method, or deserialized using their create(buff) static method.
The buffer argument contains the id and password necessary to call the LoginAction() constructor.
class AAction {
typedef std::unique_ptr<AAction> ptr;
};
class LoginAction : public AAction {
private:
std::string id;
std::string password;
bool authenticated;
public:
LoginAction(std::string id, std::string password);
virtual ~LoginAction() = default;
void execute();
static AAction::ptr create(const void* buffer);
};
2) ActionFactory: used to deserialize incoming actions, by calling the appropriate create() static method from the correct class.
class ActionFactory {
typedef std::unique_ptr<AAction> (*CreateActionFn)(const void*);
typedef std::map<RawActionType, CreateActionFn> RawFactoryMap;
RawFactoryMap rawFactoryMap;
public:
ActionFactory(Authenticator& authenticator) {
this->registerMethod(RawActionType_RawLoginAction, &LoginAction::create);
this->registerMethod(RawActionType_RawLogoutAction, &LogoutAction::create);
this->registerMethod(RawActionType_RawStandAction, &StandAction::create);
}
void registerMethod(const RawActionType &rawActionType, CreateActionFn pfnCreate);
std::unique_ptr<AAction> getAction(RawActionType rawActionType, const void* buffer);
};
Actions can be executed at any time in the code, by simply calling the execute() method, with no parameters.
Up to this point, eveything works fine.
The issue is that I now need to add some more parameters to actions that are not stored inside the password. For example in my case: an Authenticator
3) An Authenticator, to authenticate a user.
So that inside LoginAction::execute(), all I have to do is call
this->authenticator.authenticate(this->id, this->password).
Here are the changes I made for that :
I added authenticator to the LoginAction constructor :
LoginAction(Authenticator& authenticator, std::string id, std::string password);
And a field :
Authenticator& authenticator;
I added authenticator to the LoginAction::create static method :
static AAction::ptr create(const void* buffer, Authenticator& authenticator);
I modified, inside the ActionFactory constructor, the way I register method, using std::bind :
this->registerMethod(RawActions_RawLoginAction, std::bind(&LoginAction::create, std::placeholders::_1, authenticator);
But, as my function types have changed, I cannot store it in the RawFactoryMap anymore.
error: invalid cast from type ‘std::_Bind_helper ()(const void, Authenticator&), const
std::_Placeholder<1>&, Authenticator&>::type {aka
std::_Bind ((std::_Placeholder<1>,
Authenticator))(const void, Authenticator&)>}’ to type
‘ActionFactory::CreateActionFn {aka std::unique_ptr ()(const
void)}’
What is the best way to proceed, to keep a map of functions in the ActionFactory and respect the Factory pattern ?
Thanks in advance, and have a good day!
As an additional note: I am open and would be glad to read any suggestion on how to improve my code, even for some minor improvements.
First things first. With C++11, strongly prefer using to typedef. Consider the difference in readability between:
typedef std::unique_ptr<AAction> (*CreateActionFn)(const void*);
typedef std::map<RawActionType, CreateActionFn> RawFactoryMap;
and:
using CreateActionFn = std::unique_ptr<AAction>(*)(const void*);
using RawFactoryMap = std::map<RawActionType, CreateActionFn>;
It's nice when the names appear on the left instead of in an arbitrary location.
That said, now that function pointers are insufficient because you need to store state, you need to generalize to an arbitrary callable. That's what std::function is for: a type-erased callable of the provided signature:
using CreateActionFn = std::function<std::unique_ptr<AAction>(const void*)>;
This will match any callable that is copyable and which you can invoke with a const void* and get a unique_ptr<AAction>.
And while we're here, don't use std::bind:
std::bind(&LoginAction::create, std::placeholders::_1, authenticator)
use a lambda:
[authenticator](void const* ptr){ return LoginAction::create(ptr, authenticator); }
or:
[=](void const* ptr){ return LoginAction::create(ptr, authenticator); }
It may not be shorter, but it's quite a bit easier to read.

Passing a member function with two parameters to C++ STL algorithm stable_partition

I have member functions as follows
class foo
{
public:
...
bool isNotEqualId(const Agent&, const int);
std::vector<Agent> foo::extractAgents(int id);
private:
std::vector<Agent> agents;
}
The function definition is below:
bool foo::isNotEqualId(const Agent& agent, const int id)
{
return (agent.groupId != id);
}
Now, within foo, I am partitioning agents given the agent ID, in order to extract them given another parameter later on.
std::vector<Agent>& foo::extractAgents(int id)
{
std::vector<Agent>::iterator iter = std::stable_partition(agents.begin(), agents.end(), &foo::isNotEqualId(id));
// Partition to find agents that need to be removed
std::vector<Agent>::iterator extractedGroupiter = std::stable_partition(iter, agents.end(), keepAgent);
// Create a vector with the agents that need to be removed
std::vector<Agent> extractedGroup(extractedGroupiter, agents.end());
// Erase them from the agents vector
agents.erase(extractedGroupiter, agents.end());
return extractedGroup;
}
using std::stable_partition used to work when used with functions that had a fixed group value, such as
bool isNotGroup0(const Agent& a)
{
return a.groupId != 0;
}
However, now I want to use a member function that takes in two parameters, so the group ID can be a parameter. stable_partition takes in a unary predicate which is causing me the issue. I've tried using std::bind2nd with std::mem_fun in order to bind the 2nd parameter when passing it to stable_partition, but it results in errors with mem_fun having no instance of the overloaded function.
I've also tried a functor solution such as here, which suggests using a std::binary_function, however it understandably results in an error of term does not evaluate to a function taking 1 arguments. I'm using VS2010. Any Pointers?
Since you're using Visual Studio 2010, and I don't know if lambdas are available in that version, use a function object:
struct AgentFunctor
{
int id_;
AgentFunctor(int id) : id_(id) {}
bool operator()(const Agent& agent) const
{ return agent.groupId != id_; }
};
//...
AgentFunctor af(id);
std::vector<Agent>::iterator iter = std::stable_partition(agents.begin(), agents.end(), af);
You can just use a lambda:
std::stable_partition(agents.begin(), agents.end(),
[nGroupID, foo](x){
return foo.isNotEqualID(x, nGroupID);});
Just noticed the VS2010 comment, which I'm pretty sure doesn't have lambdas, in which case you have to create the function object more manually, such as in PaulMcKenzie's answer.

Cannot call member function std::string class::function() without object

I know it may seem like this has been asked before but I've looked around and the static method didn't work for me. Here's my code:
struct Customer {
public:
string get_name();
private:
string customer,first, last;
};
Here's where I call the function:
void creation::new_account() {
Customer::get_name(); //line it gives the error on.
}
Here's an example of some code that compiles fine.
struct Creation { public: string get_date(); private: string date; };
then I call it the same way
void Creation::new_account() { Creation::get_date();}
Hence my confusion why one works and the other doesn't.
EDIT: Ok I get it, I just realized I was calling a function of another struct inside a function definition that's part of a different class. I got it, thanks to all who answered
It is not declared static (needs to be static std::string get_name();). However, get_name() for Customer is a specific attribute of a Customer instance so having it static does not make sense, that is the same name for all instances of Customer. Declare an object of Customer and use it. It would make sense to have the name provided to the constructor of Customer, as surely a customer cannot exist without a name:
class Customer {
public:
Customer(std::string a_first_name,
std::string a_last_name) : first_name_(std::move(a_first_name)),
last_name_(std::move(a_last_name)) {}
std::string get_name();
private:
std::string first_name_;
std::string last_name_;
};
Declare an instance of Customer:
Customer c("stack", "overflow");
std::cout << c.get_name() << "\n";
Since your get_name is not declared static, it is a member function.
You probably need some constructors in your Customer class. Assuming you have some, you could code
Customer cust1("foo123","John","Doe");
string name1 = cust1.get_name();
You need an object (here cust1) to call its get_name member function (or method).
Time to spend many hours reading a good C++ programming book.
"The static method didn't work for me". It's not a method it's how the language works.
If you want to call some method without a concrete object, you need it to be static. Otherwise, you need an object.
Your code will work with one of the following :
struct Customer {
public:
static string get_name();
private:
string customer,first, last;
};
or
void creation::new_account() {
Customer c;
//stuff
c.get_name();
}

Passing this to an object within an object during the constructor call

I am trying to iron out my first compile in a long time, and I think this is the last hurdle.
I am trying to create this type of hierarchy in my design.
class chin_
{
private:
charon_* engine;
public:
chin_();
chin_(charon_ &handle)
{
engine = handle;
}
~chin_();
};
//////////////
class charon_ {
private:
chin_ engine_input;
public:
charon_(){
engine_input = chin_(this);
}
~charon_();
};
I am getting errors that tell me there is no matching function for call to
'chio::chin_::chin()'
it also says, mind you this is only when I change the constructor to charon_&
public:
chin_(const charon_ &handle)
{
engine = handle;
}
sys/../headers/chio.h:104:5: note: no known conversion for argument 1 from ‘charon::charon_* const’ to ‘const charon::charon_&’
When I use the * instead of & I get this instead, which is by far more baffling.
sys/../headers/chio.h:104:5: note: chio::chin_::chin_(const charon::charon_*)
sys/../headers/chio.h:104:5: note: candidate expects 1 argument, 0 provided
I've tried this and that, and I figure it is probably something super simple. I've tried to match my code up squarely with the examples I've found though so I don't know what else I should be trying, I'd like to be able to figure this sort of stuff out on my own. I just am not having any luck with it.
EDIT:
I update the code but I left the updated error for the bottom.
sys/chin.cpp:19:14: error: cannot convert ‘charon::charon_’ to ‘charon::charon_*’ in assignment
It takes me to this code
chin_::chin_(charon_ &handle) {
engine = handle;
}
engine is defined as
charon_* engine; and handle appears to be an address and should fall right into place, but it isn't. I think I am not using this correctly.
When you declare something like this :
chin_ engine_input;
chin_ needs a constructor with no parameters or you have to pass the parameters to it in the initializer list, otherwise you will get the error about no matching constructor.
What you can do is either have a default constructor that takes no params. Or make engine_input a pointer and create it with :
engine_input = new chin_(handle);
Alternatively you can pass handle to chin_ in the initializer list like this :
foo::foo(charon* handle):
chin_(handle)
{
}