有很多方法可以使容器(例如队列)容纳不同类型的对象。最经典的有一个std::pair<void*, int>
元素,其中element.first
是指向对象的指针并element.second
映射到对象类型。
在找出下划线对象的类型之后,所有这些方法(我知道)都涉及一些运行时开销(例如一些 switch on element.second
) 。queue.pop()
我的问题是:是否有可能完全消除这种运行时开销?毕竟,对象类型在对象(指向对象的指针)被推入队列之前就已经知道了。
有很多方法可以使容器(例如队列)容纳不同类型的对象。最经典的有一个std::pair<void*, int>
元素,其中element.first
是指向对象的指针并element.second
映射到对象类型。
在找出下划线对象的类型之后,所有这些方法(我知道)都涉及一些运行时开销(例如一些 switch on element.second
) 。queue.pop()
我的问题是:是否有可能完全消除这种运行时开销?毕竟,对象类型在对象(指向对象的指针)被推入队列之前就已经知道了。
如果您静态知道元素的类型,则可以制作模板数据存储:
#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(); }
}
用法:
// 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>(); }
如果你想让开关隐式,我想你必须使用多态(如果类型共享一个公共接口)。使用重载的另一种方法是让对的第二个元素是指向处理该特定类型的函数的指针,而不是类型标记。如果您使用的是 C++11,您甚至可以使用 lambda 表达式。
第一个选项会让你得到类似的东西:
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();
}
}
而第二种选择是:
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);
}