Reputation: 9
There are bunch of methods to make containers (e.g. queue) to hold objects of different types.
The most classical to have an std::pair<void*, int>
element, where element.first
is the pointer to the object and element.second
mapped to the object type.
All those method (which I know) involves some runtime overhead (e.g. some switch on element.second
) after queue.pop()
to find out the type of the underline object.
My question is: is it possible eliminate this runtime overhead completely? After all, the object type has been known just before the object (pointer to the object) pushed to the queue.
Upvotes: 0
Views: 76
Reputation: 3230
If you want to make the switch implicit, I guess you have to use polimorphism (if the types share a common interface). Another way to use overloading is to have the second element of the pair be a pointer to a function that handles that specific type, rather than a type tag. If you're using C++11, you can even use lambda expressions.
The first option would get you to something like:
class IMyInterface
{
public:
virtual void handle() = 0;
};
class AClass : public IMyInterface
{
public:
virtual void handle()
{ /*handles (*this) object*/ }
};
class BClass : public IMyInterface
{
public:
virtual void handle()
{ /*handles (*this) object*/ }
};
void handle_elements(std::vector<IMyInterface*>& v)
{
while (!v.empty)
{
IMyInterface* obj = v.back();
v.pop_back();
obj->handle();
}
}
while the second option would be:
typedef void (*handler)(void*);
static void handle_int(void* intptr)
{
int* iValue = (int*)intptr;
//Handles iValue
}
static void handle_complex_object(void* ccptr)
{
ComplexClass* ccValue = (ComplexClass*)ccptr;
//Handles ccValue
}
void handle_elements(vector<pair<void*, handler>>& v)
{
while (!v.empty)
{
pair p = v.back();
v.pop_back();
p.second(p.first);
}
}
void fill_queue(vector<pair<void*, handler>>& v)
{
v.push_back(pair<void*, handler>(new int(10), handle_int);
v.push_back(pair<void*, handler>(new ComplexClass(), handle_complex_object);
}
Upvotes: 0
Reputation: 477444
If you know the type of the element statically, you can make a templated data store:
#include <queue>
#include <utility>
namespace store
{
template <typename T> struct wrapper { static std::queue<T> data; };
template <typename T> std::queue<T> wrapper<T>::data;
template <typename T> void put(T const & x) { wrapper<T>::data.push(x); }
template <typename T> void put(T && x) { wrapper<T>::data.push(std::move(x)); }
template <typename T> T get()
{
T x = wrapper<T>::data.back();
wrapper<T>::data.pop();
return x;
}
template <typename T> bool empty() { return wrapper<T>::data.empty(); }
}
Usage:
// push on the queue for decltype(a)
store::put(a);
// push on the Foo-queue
store::put(Foo(1, 'true', false));
// pop from the Bar-queue
if (!store::empty<Bar>()) { auto c = store::get<Bar>(); }
Upvotes: 3