I'm creating a job queue. The job will be created in thread A, then the job will be sent to thread B and thread B will do the job. After the job has been done, the job will be sent back to thread A.
#include <functional>
#include <iostream>
#include <memory>
using namespace std;
template<typename T, typename... Args>
class Job
{
public:
Job(std::weak_ptr<T> &&wp, std::function<void(const Args&...)> &&cb)
: _cb(std::move(cb)),
_cbWithArgs(),
_owner(std::move(wp)) {}
public:
template<typename... RfTs>
void bind(RfTs&&... args)
{
// bind will copy args for three times.
_cbWithArgs = std::bind(_cb, std::forward<RfTs>(args)...);
}
void fire()
{
auto sp = _owner.lock();
if (sp)
{
_cbWithArgs();
}
}
private:
std::function<void(const Args& ...)> _cb;
std::function<void()> _cbWithArgs;
std::weak_ptr<T> _owner;
};
struct Args
{
Args() = default;
Args(const Args &args)
{
cout << "Copied" << endl;
}
};
struct Foo
{
void show(const Args &)
{
cout << "Foo" << endl;
}
};
int main()
{
using namespace std::placeholders;
shared_ptr<Foo> sf (new Foo());
Args args;
// Let's say here thread A created the job.
Job<Foo, Args> job(sf, std::bind(&Foo::show, sf.get(), _1));
// Here thread B has finished the job and bind the result to the
// job.
job.bind(args);
// Here, thread A will check the result.
job.fire();
}
The above codes compiles and works. But it gives the following results (g++ 4.8.4 & clang have the same results):
Copied
Copied
Copied
Foo
There are three copies! Not acceptable, I don't know where I did wrong. Why three copies? I googled and find a method from here: https://stackoverflow.com/a/16868401, it only copys params for one time. But it has to initialize the bind function in constructor.
Thanks, Piotr Skotnicki. Unfortunately, I don't have a C++14 compiler. So, let's make the Args movable:
struct Args
{
Args() = default;
Args(const Args &args)
{
cout << "Copied" << endl;
}
Args(Args &&) = default;
Args& operator=(Args &&) = default;
};
Now, it copys just one time :)
Finally, I adopted the codes from this thread https://stackoverflow.com/a/16868151/5459549. The template gen_seq is true ART, I must say.
The first copy is made by the std::bind itself:
std::bind(_cb, std::forward<RfTs>(args)...)
as it needs to store decayed-copies of its arguments.
The other two copies are made by the assignment to _cbWithArgs which is of type std::function (§ 20.8.11.2.1 [func.wrap.func.con]):
template<class F> function& operator=(F&& f);
18 Effects: function(std::forward<F>(f)).swap(*this);
where:
template<class F> function(F f);
9 [...] *this targets a copy of f initialized with std::move(f).
That is, one copy for the parameter of a constructor, and another one to store argument f.
Since Args is a non-movable type, an attempt to move from a result of a call to std::bind falls back to a copy.
It doesn't seem reasonable in your code to store the results of job execution in a std::function. Instead, you can store those values in a tuple:
template <typename T, typename... Args>
class Job
{
public:
Job(std::weak_ptr<T> wp, std::function<void(const Args&...)> &&cb)
: _cb(std::move(cb)),
_owner(wp) {}
public:
template<typename... RfTs>
void bind(RfTs&&... args)
{
_args = std::forward_as_tuple(std::forward<RfTs>(args)...);
}
void fire()
{
auto sp = _owner.lock();
if (sp)
{
apply(std::index_sequence_for<Args...>{});
}
}
private:
template <std::size_t... Is>
void apply(std::index_sequence<Is...>)
{
_cb(std::get<Is>(_args)...);
}
std::function<void(const Args&...)> _cb;
std::weak_ptr<T> _owner;
std::tuple<Args...> _args;
};
DEMO
Related
I have the following code:
class A{
public:
A() {}
void foo(const B& b) {
int a = b.a();
}
};
template<class T, typename ... ARGS>
std::function<void()> * invoke(T *t, void(T::* fn)(ARGS...), ARGS... args) {
//Create a new std::function on the heap to be executed later
std::function<void()> *f = new std::function<void()>([=]() { (t->*fn)( args... ); });
return f;
}
int main(void) {
A myA;
B myB(5, 6, 7);
std::function<void()> *fn = invoke(&myA, &A::foo, myB);
}
The purpose of which is to be able to create a generic std::function from a member function pointer (and object pointer) on the heap for later execution.
My problem is, the compiler doesn't seem to be able to figure out how to expand the invoke template correctly and I get the following error:
template argument deduction/substitution failed:
inconsistent parameter pack deduction with 'const B&' and 'B'
I would like the semantics for my invoke() function to stay the same (i.e. object *, member function *, arguments...).
Is there a way to maintain these semantics while still allowing the compiler to figure out the correct template deduction?
Thanks!
EDIT
I can get it to work if I do the following:
template<class T, typename F, typename ... ARGS>
std::function<void()> * invoke(T *t, F const &fn, ARGS... args) {
std::function<void()> *f = new std::function<void()>([=]() { (t->*fn)( args... ); });
return f;
}
However, this does not fully meet my needs because two copies are made of the argument instead of one. I would like only a single copy to occur when I create the new std::function allocated on the heap. The arguments should still be passed in by reference to math the signature of the member function.
Your invoke function is already known as std::bind and if you want to ensure that parameters to foo are not copied, then combine bind with cref:
#include <functional>
struct B {
int a() const { return 1; }
};
struct A {
void foo(const B& b) {
int a = b.a();
}
};
int main(void) {
A myA;
B myB;
auto* fn = new std::function<void()>(std::bind(&A::foo, &myA, std::cref(myB)));
}
First of all, you should really be using std::forward when dealing with parameter packs. Right now you are taking all parameters as values.
Secondly, compilation fails because type deduction conflicts between void(T::* fn)(ARGS...) and ARGS... args. The compiler will get confused about whether to take types from args or from your function. For example, A::foo takes a const B& but you are giving it a value type B as well, which leads to a conflict. So you actually need two separate parameter packs to avoid this.
#include <functional>
#include <utility>
// you didn't provide a definition of B, so this is what I had to come up with
struct B {
int x;
int y;
int z;
int a() const {
return x;
}
};
class A{
public:
A() {}
void foo(const B& b) {
int a = b.a();
}
};
// you don't actually need to create a function on the heap
template<class T, typename ... FARGS, typename ...ARGS>
std::function<void()> invoke(T *t, void(T::* fn)(FARGS...), ARGS &&... args) {
return [&, t]() { (t->*fn)( std::forward<ARGS>(args)... ); };
}
int main(void) {
A myA;
B myB{5, 6, 7};
std::function<void()> fn = invoke(&myA, &A::foo, myB);
}
Alternatively, you could also use std::bind which does exactly what you are trying to accomplish:
std::function<void()> fn = std::bind(&A::foo, &myA, myB);
Arguments of invoke and arguments of your member function are not the same. One gets a const reference, the other does not. This needs to be reflected in the types.
template<class T,
typename ... ARGS,
typename ... ARGS2> // <---- !!
std::function<void()> * invoke(T *t,
void(T::* fn)(ARGS2...) // <---- !!
ARGS&&... args) { // you do want perfect forwarding
I figured out a solution that works for me based upon everyone's answers and comments.
In my application, I need to ensure that one, and only one, copy of the arguments to the function being invoked is made because that function will be executed within a different thread at a different time and the original data might not be available (e.g. a temporary variable on the stack). I had modified my code, as suggested, to use perfect forwarding within my template functions. This helped cut down on unnecessary copies significantly, however, I was still getting an extra copy within the lambda in my invoke function. It turns out, I had written the move constructor of my data type incorrectly so, when the lambda created a temporary copy of the data, it had to be copied twice.
Here are snippets of my working code (with my example datatype B):
class B {
public:
B() : _a(1), _b(2), _c(3) {
}
B(int a, int b, int c) : _a(a), _b(b), _c(c) {
}
//Copy Constructor
B(const B &v) : _a(v._a), _b(v._b), _c(v._c) {
copyCount++;
}
//Move Constructor
B(const B&& rhs): _a(rhs._a), _b(rhs._b), _c(rhs._c)
{
}
B& operator=(const B &v) {
this->_a = v._a;
this->_b = v._b;
this->_c = v._c;
copyCount++;
return *this;
}
~B() {
}
inline int a() const { return _a; }
static int copyCount;
private:
int _a;
int _b;
int _c;
};
template<class T, typename ... ARGSF, typename ... ARGS>
inline static void invoke(T *t, void(T::*fn)(ARGSF...), ARGS&&... args) {
std::function<void()> *f = new std::function<void()>([=]() { (t->*fn)( args... ); });
//Queue in the parent thread
if (!t->_parentThread->queueInvokable(f)) delete f;
}
template<class T>
inline ConnectionHandle connect(T* t, void(T::* fn)(ARGS...)) {
const auto lambda = [=](ARGS&&... args) { T::invoke(t, fn, args...); };
return connect(lambda);
}
I have also shown here another function, connect, which saves a lambda to be called later that in turns calls the invoke function.
With all this, only a single copy of the datatype is made as long as
a) The argument to the member function (fn) is of a reference type
b) The datatype has a working move constructor
What I'm trying to achieve is creating a struct which stores any kind of method. I can later call struct_object.run() to run the method I've stored.
This method can return any kind of value and, most importantly, use any amount of parameters; however, I can't get around the "any amount of parameters" issue.
Mind you, the following code doesn't even build, mostly because I have no clue on what the correct syntax would be like.
ApplicationPair.h
template<typename T, typename... Args>
struct ApplicationPair
{
ApplicationPair(boost::function<T()> func, Args... arguments )
{
_func = func(Args::arguments...);
}
ApplicationPair() = delete;
void run();
boost::function<T(Args...)> _func;
};
#endif
And then, what I'd like to do is the following:
main.cpp
template<typename T, typename... Args>
void ApplicationPair<T,Args...>::run()
{
this->_func;
}
//TEST
int counter = 0;
void HelloWorld()
{
std::cout << "HelloWorld\n";
}
void printNumber(int i)
{
std::cout << "Print: " << i << std::endl;
}
void increaseCounter(int x)
{
counter+=x;
}
int main()
{
ApplicationPair<void> p1(HelloWorld);
ApplicationPair<void> p2(printNumber, 5);
ApplicationPair<void> p3(increaseCounter, 10);
p1.run();
p2.run();
p3.run();
return 0;
}
Basically, the methods I want to store shouldn't be modified or adapted in any way: I want to be able to create any kind of method without caring about the fact that struct ApplicationPair will store it for its own personal use.
All I get with this though is a long string of errors like:
error: in declaration ‘typename boost::enable_if_c<(! boost::is_integral::value), boost::function&>::type boost::function::operator=(Functor)’
In the below line:
ApplicationPair<void> p2(printNumber, 5);
you have to specify all types in template arguments list, not only void as return type, int as argument of constructor should also be added. Now args... is empty. What is wrong. The same with p3.
Make constructor as templated method taking paramters pack as argument for your callable:
template<class F, class ... Args>
ApplicationPair(F&& func, Args... arguments )
{
_func = boost::bind(std::forward<F>(func),arguments...);
}
then args... can be deduced when invoking constructor. Your class template takes only a type for return value.
template<class Ret>
struct ApplicationPair {
template<class F, class ... Args>
ApplicationPair(F&& func, Args... arguments )
{
_func = boost::bind(std::forward<F>(func),arguments...);
}
ApplicationPair() = delete;
void run() {
this->_func();
}
boost::function<Ret()> _func;
};
In constructor boost::bind is used to bind passed parameters to callable. You don't store parameters anywhere, therefore they must be bound in functor created by boost::bind.
Uses:
ApplicationPair<void> p1(HelloWorld);
ApplicationPair<void> p2(printNumber, 5);
ApplicationPair<void> p3(increaseCounter, 10);
Demo
Don't use boost::bind, it is limited to handle only max 9 arguments.
You've already gotten an answer but here's a C++17 alternative capable of deducing the return value type as well as the argument types of the function using a deduction guide, making both the return type and argument types part of the ApplicationPair<> type. I've chosen to store the arguments separately in a std::tuple<Args...>.
boost::function can be replaced with std::function in this example in case you later decide to go with the standard:
#include <boost/function.hpp>
#include <iostream>
#include <type_traits>
#include <tuple>
template<typename T, typename... Args>
struct ApplicationPair {
ApplicationPair() = delete;
ApplicationPair(Func func, Args... args) :
_func(func),
// store the arguments for later use
arguments(std::make_tuple(std::forward<Args>(args)...))
{}
decltype(auto) run() { // I'd rename this: decltype(auto) operator()()
return std::apply(_func, arguments);
}
boost::function<T(Args...)> _func;
std::tuple<Args...> arguments;
};
// deduction guide
template<typename Func, typename... Args>
ApplicationPair(Func, Args...) ->
ApplicationPair<std::invoke_result_t<Func, Args...>, Args...>;
int counter = 0;
void HelloWorld()
{
std::cout << "HelloWorld\n";
}
void printNumber(int i)
{
std::cout << "Print: " << i << std::endl;
}
int increaseCounter(int x) // changed return type for demo
{
counter+=x;
return counter;
}
int main()
{
// full deduction using the deduction guide
ApplicationPair p1(HelloWorld);
ApplicationPair p2(printNumber, 5);
ApplicationPair p3(increaseCounter, 10);
p1.run();
p2.run();
std::cout << p3.run() << '\n';
std::cout << p3.run() << '\n';
}
see example below live : https://onlinegdb.com/Hkg6iQ3ZNI
#include <iostream>
#include <utility>
#include <type_traits>
class A
{
public:
A(int v=-10):v_(v){}
void print()
{
std::cout << "called A: " << v_ << std::endl;
}
private:
int v_;
};
void f(int v)
{
std::cout << "called f: " << v << std::endl;
}
template<typename T,typename ... Args>
void run(A&& a,
T&& t,
Args&& ... args)
{
a.print();
t(std::forward<Args>(args)...);
}
template<typename T,typename ... Args>
void run(T&& t,
Args&& ... args)
{
run(A(),
std::forward<T>(t),
std::forward<Args>(args)...);
}
int main()
{
int v_function=1;
int v_a = 2;
run(f,v_function);
return 0;
}
The code above compiles, runs and print (as expected):
called A: -10
called f: 1
but if the main function is modified to:
int main()
{
int v_function=1;
int v_a = 2;
run(f,v_function);
// !! added lines !!
A a(v_a);
run(a,f,v_function);
return 0;
}
then compilation fails with error:
main.cpp:30:6: error: no match for call to ‘(A) (void (&)(int), int&)’
t(std::forward(args)...);
~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
which seems to indicate that even when an instance of A is passed as first argument, the overload function
void(*)(T&&,Args&&...)
is called, and not
void(*)(A&&,T&&,Args&&...)
With
template<typename T,typename ... Args>
void run(A&& a,
T&& t,
Args&& ... args)
a is not a forwarding reference, but an rvalue reference. That means when you do run(a,f,v_function); that function will not be selected because a is an lvalue and those can't be bound to rvalue references. There are two quick ways to fix this. First, use std::move on a like
run(std::move(a),f,v_function);
but this isn't great. a isn't actually moved in the function so you are kind of violating the principle of least surprise.
The second option is to make A in the function a template type so it becomes a forwarding reference and then you can constrain it to be of type A like
template<typename A_, typename T,typename ... Args, std::enable_if_t<std::is_same_v<std::decay_t<A_>, A>, bool> = true>
void run(A_&& a,
T&& t,
Args&& ... args)
{
a.print();
t(std::forward<Args>(args)...);
}
Your code works, if you are calling run with an rvalue.
Playable example here.
As NathanOliver already sad: void run(A&& a, T&& t, Args&& ... args) expects an rvalue reference.
Basic idea of an rvalue reference: You are passing an rvalue to a function (e.g. a string literal). That value will be copied to the function. This work is unnecessary. Instead, you are just "moving" the reference to that value, so that it is "owned" by a different part of your program. Move constructors are a good starting point for understanding this problem.
So Im using a simple example to try to understand variadic templates and some tmp techniques. The example consists on a Timer class which has a toc() method. The toc methods its used to stop the timer and call a function which decides what to do (print it, save it in a variable...)
So I have coded this idea like this (ive removed the timing bits)
class VerbosePolicy {
public:
VerbosePolicy() {}
explicit VerbosePolicy(const std::string &message) : m_message(message) {}
VerbosePolicy(VerbosePolicy &&other) { m_message = other.m_message; }
void operator()(double time) { std::cout << m_message << time << std::endl; }
private:
std::string m_message;
};
template <typename Policy, typename... Args> class Timer {
public:
Timer(Args... args) : m_policy(Policy(std::forward<Args>(args)...)) {}
void toc(double time) { m_policy(time); }
private:
Policy m_policy;
};
Here I create a Timer with a Policy and call the ctor of the Policy with the parameter pack. This way I can control how the Policy works (for example, I could pass a variable and store there the result).
Now, I want to use this
int main(int argc, char **argv) {
std::string string = "Elapsed time";
Timer<VerbosePolicy> timer(string);
timer.toc(1.0);
}
The problem here is that the compiler is not able to determine that the string is part of the parameter pack, and its trying to match it to the Policy time, which fails.
I have tried adding a default argument for the Timer ctor
Timer(Args... args, Policy policy = Policy())
But this also fails, as its still trying to match de string to the policy type (in this case, it tries to call the second ctor, which fails because its marked as explicit. If I remove it, it compiles, but works wrong because the policy value its incorrect).
Everything works fine if I write
Timer<VerbosePolicy, std::string> timer(string)
as it doesn't need to deduce the variadic template anymore.
Is there anyway I can avoid writing the std::string?
Thanks!
EDIT:
So to be complete and address some of the problems talked in the comments of the valid answer, I have been trying to deactivate the variadic constructor when the parameter its of the same type as the Timer, without success.
My approach has been
template <typename T, typename... Tail> struct first_of { using type = T; };
template <typename Policy> class Timer {
public:
template <
typename... CArgs,
std::enable_if_t<!std::is_same<Timer<Policy>,
typename first_of<CArgs...>::type>::value,
int> = 0>
Timer(CArgs &&... args) : m_policy(std::forward<CArgs>(args)...) {}
Timer(const Timer<Policy> &other) : m_policy(other.m_policy) {}
void toc(double time) { m_policy(time); }
private:
Policy m_policy;
};
int main(int argc, char **argv) {
std::string string = "Elapsed time";
Timer<VerbosePolicy> timer(string);
Timer<VerbosePolicy> timer2(timer);
timer.toc(1.0);
}
But the compiler still tries to use the variadic constructor for timer2. Im not sure why its trying to do this, since the two types passed to std::is_same should be equal, and therefore the ctor should be deactivated.
What am I misunderstanding?
Thanks again!
Did you try to make your constructor template instead?
Like :
template <typename Policy> class Timer {
public:
template<typename ...Args>
Timer(Args && ... args) : m_policy(std::forward<Args>(args)...) {}
void toc(double time) { m_policy(time); }
private:
Policy m_policy;
};
Btw, you are using std::forward in the wrong way. What you are doing is that :
template<typename T>
void foo(T v) {
std::forward<T>(v);
}
In such code, T is a non reference value. So forward it here means : T&& so it is the same as "move"
if you want to forward reference, you must use forwarding reference :
template<typename T>
void foo(T &&v) {
std::forward<T>(v);
}
If the argument is a lvalue reference, here T is a T& and if the argument is a rvalue reference, T is a T and by forwarding reference v is respectively a T& &&so a T& and T && so a T&& ;)
EDIT :
As said in commentary, this code does not work when you give a Timer to the constructor.
There is some way to avoid this issue, SFINAE can help you for example ;)
EDIT 2 :
You want to keep a track of your Args ... as you said in commentary.
Let's say you have a class like that :
template<typename ...Args>
class Foo {
public:
Foo(Args... args) : noexcept m_tuple{std::move(args)...} {}
private:
std::tuple<Args...> m_tuple;
};
You want to deduce type : there is two ways :
1) Before C++ 17 :
template<typename ...Args>
Foo<Args...> make_foo(Args ...args) {
return {args...};
}
auto d = make_foo(5, 3.0); // Foo<int, double>
2) After c++ 17
template<typename ...Args>
Foo(Args...) -> Foo<Args...>;
Foo foo{3.0, "Lol"s}; // Foo<double, std::string>
The name for this is deduction guide.
Goal: Having function dispatching working as intended. The minimal example code should speak for itself. I want to support tasks: Named task, that are implemented in their own class, and simpler task, specified using lambda. Ideally, anything that can be converted to std::function<void (void)> should work.
#include <iostream>
#include <memory>
#include <functional>
// A Base class for my tasks
class BaseTask
{
public:
virtual void blah() = 0;
};
// An important enough tasks that it gets to have its
// own class.
class NamedTask : public BaseTask
{
public:
virtual void blah()
{
std::cout << "Hey !" << std::endl;
}
};
// A wrapper around simpler tasks. (lambda)
class GenericTask : public BaseTask
{
public:
GenericTask(const std::function<void (void)> fct) :
fct_(fct) {}
virtual void blah() override
{
fct_();
}
private:
std::function<void (void)> fct_;
};
void enqueue(std::shared_ptr<BaseTask> t)
{
// store in queue.
// We'll just call it here for the sake of the example
t->blah();
}
template<typename Callable>
//typename std::enable_if<!std::is_base_of<BaseTask, Callable>::value>::type
//typename std::enable_if<!std::is_base_of<std::shared_ptr<BaseTask>, Callable>::value>::type
void enqueue(const Callable &c)
{
auto t = std::make_shared<GenericTask>(c);
t->blah();
}
int main()
{
auto named = std::make_shared<NamedTask>();
enqueue(named); // doesn't compile: tries to call the templated enqueue.
enqueue([] () -> bool { std::cout << "Lamda" << std::endl; });
}
Problem: I don't manage to write a proper enable_if template. The commented lines in the example is what I tried.
The first one doesn't work because Callable is of type std::shared_ptr<NamedTask>, which is not a child of BaseTask.
The second one fails too, presumably because std::shared_ptr<NamedTask> does not derive from std::shared_ptr<BaseTask>.
You have two cases: your callable is convertible to shared_ptr<BaseTask>, or not. Checking the base is incorrect as shared_ptr<NamedTask> is not related by class hierarchy to shared_ptr<BaseTask>, but you can construct a shared_ptr<BaseTask> from it.
That is:
// is convertible to shared_ptr<BaseTask>
void enqueue(std::shared_ptr<BaseTask> t);
// is NOT convertible to shared_ptr<BaseTask>
template<typename Callable>
typename std::enable_if<
!std::is_convertible<Callable, std::shared_ptr<BaseTask>>::value
>::type
enqueue(const Callable &c);
Alternatively, you can think of the two cases as constructible/not constructible:
template<typename Callable>
typename std::enable_if<
!std::is_constructible<std::shared_ptr<BaseTask>, Callable>::value
>::type
enqueue(const Callable &c);
Third alternative is to condition the function template enqueue on anything that is callable with zero arguments:
template<typename Callable>
auto enqueue(const Callable &c) -> decltype(c(), void())