I am currently in the process of writing a method execution queue in C++x0. I have implemented and verified the basic queue mechanism but want to amend it with an option to have push()
automatically remove all previous calls to a specific method:
queue.push(this, &Obj::foo, 1);
queue.push(this, &Obj::foo, 2);
queue.push(this, &Obj::foo, 3);
should be the same as merely calling
queue.push(this, &Obj::foo, 3);
My code thus far looks like this:
Queue.h:
#pragma once
#include <functional>
#include <vector>
using std::vector;
using std::function;
using std::bind;
class Queue
{
private:
struct functioncall {
std::function<void()> call;
};
vector<functioncall> queue;
public:
Queue();
~Queue();
template<typename T, typename F, typename... Args>
int push(T, F , Args... args);
int pop();
bool empty();
size_t size();
};
template<typename T, typename F, typename... Args>
int Queue::push(T instance, F func, Args... args)
{
functioncall newelem = { bind(func, instance, args...) };
queue.push_back(newelem);
return queue.size();
}
Queue.cpp:
#include "Queue.h"
Queue::Queue() : queue()
{
}
Queue::~Queue()
{
delete &queue;
}
int Queue::pop()
{
if(!queue.empty())
{
queue.front().call();
queue.erase(queue.begin());
return queue.size();
}
return 0;
}
bool Queue::empty()
{
return queue.empty();
}
size_t Queue::size()
{
return queue.size();
}
I have already prepared the vector queue
to take a struct in wich I want to not only save the result of std::bind
but also the pointer to the method being called so I can look for that pointer and remove the old entries.
The issue is that the functions passed to push()
can take an arbitrary amount of arguments. Is there a generic pointer type (it doesn't have to be executable, just be the same when I repeatedly push the same function to the queue) that can do that?
Per 5.2.10p10, you can cast a pointer to member function T::*(A1, A2, ...)
to another pointer to member function type U::*(B1, ...)
and back with no loss of information; std::less
can compare pointers to member functions so by casting to a dummy pointer-to-member type void (Impl::*)()
you can compare pointer to member functions with the same signature.
However, it is not guaranteed that pointer to member functions with different signatures will compare different when cast to the same pointer to member type, so you will need to encode the signature in your comparable type. typeid
will work here:
auto key = std::make_pair(&typeid(F), reinterpret_cast<void (Queue::*)()>(func));
This assumes that F
is indeed a pointer to member function; if the user attempts to pass some other callable object then this will break.
std::function::target<>()
can be used to check wrapped function type:
template <class F> bool is_same_call(const functionalcall& prevCall, F newCall)
{
const F* pf = prevCall.call.target<F>();
return pf ? *pf == newCall : false;
}
Note that std::function::target()
will return nullptr
if function wrapped with std::function
object has type different from F
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With