仅使用静态多态性的异构容器 [英] Heterogenous container using only static polymorphism
问题描述
我的目标是实现一个容器(这里是一组堆栈,每种类型一个),该容器同时接受许多不同类型的对象.使用void指针(或所有存储类型的通用基类)和运行时类型标识(RTTI),在运行时这样做将是微不足道的.由于容器将要持有的所有类型在编译时都是已知的,因此有可能(或可能没有)使用模板来创建这样的类.我知道boost::variant
已经提供了类似的功能,但是它要求将存储的类型作为模板参数列出,就像在boost::variant< int, std::string > v;
中一样.
我真正要寻找的是一个类,该类在每次创建等效于push()
的新模板专业化时都向其自身透明地添加匹配的(内部)数据结构.该类的用法如下所示:
int main()
{
MultiTypeStack foo;
//add a double to the container (in this case, a stack). The class would
//..create a matching std::stack<double>, and push the value to the top.
foo.push<double>(0.1);
//add an int to the container. In this case, the argument type is deduced.
//..The class would create a std::stack<int>, and push the value to the top.
foo.push(123);
//push a second double to the internal std::stack<double>.
foo.push<double>(3.14159);
std::cout << "int: " << foo.top<int>() << "\n"; //"int: 123"
std::cout << "double: " << foo.top<double>() << "\n";//"double: 3.14159"
return 0;
}
以朴素的实现为例:
template<typename T> struct TypeIndex;
template<> struct TypeIndex<int>{enum{i = 0};};
template<> struct TypeIndex<double>{enum{i = 1};};
class MultiTypeStack
{
public:
template<typename T>
void push(const T &val){std::get<TypeIndex<T>::i>(stacks_).push(val);}
template<typename T>
void pop(){std::get<TypeIndex<T>::i>(stacks_).pop();}
template<typename T>
T top(){return std::get<TypeIndex<T>::i>(stacks_).top();}
private:
std::tuple<std::stack<int>, std::stack<double>> stacks_;
};
创建一个std::unordered_map<std::type_index, std::unique_ptr<unknown>>
.您输入的访问代码将进行输入并找到适当的条目.然后static_cast
unknown
变为依赖T
的类型,该类型保存您的堆栈.
确保unknown
是stack_holder<T>
的基数,并且unknown
具有virtual
析构函数.
这可能不完全是您想要的,但是C ++类型系统是纯的:以后的表达式不能更改以前的"类型.
如果将类型链接在一起,则可以构造更复杂的类型,但这只是在隐藏它们的同时列出了这些类型.
如果对象是单例对象,则使用static
当地人的某些骇客可能会起作用.
My goal is to implement a container (here a set of stacks, one for each type) that accepts many different types of objects simultaneously. This would be trivial to do at runtime, using void pointers (or a common base class for all stored types) and runtime type indentification (RTTI). Since all types the container is going to hold are known at compile time, it may (or may not) be possible to make such a class using templates. I am aware that boost::variant
already provides similar functionality, but it requires that the stored types are listed as template arguments, as in boost::variant< int, std::string > v;
.
What I'm really looking for is a class that transparently adds a matching (internal) data strucure to itself each time a new template specialization of the equivalent of push()
is created. The usage of the class would look like this:
int main()
{
MultiTypeStack foo;
//add a double to the container (in this case, a stack). The class would
//..create a matching std::stack<double>, and push the value to the top.
foo.push<double>(0.1);
//add an int to the container. In this case, the argument type is deduced.
//..The class would create a std::stack<int>, and push the value to the top.
foo.push(123);
//push a second double to the internal std::stack<double>.
foo.push<double>(3.14159);
std::cout << "int: " << foo.top<int>() << "\n"; //"int: 123"
std::cout << "double: " << foo.top<double>() << "\n";//"double: 3.14159"
return 0;
}
A naïve implementation as an example:
template<typename T> struct TypeIndex;
template<> struct TypeIndex<int>{enum{i = 0};};
template<> struct TypeIndex<double>{enum{i = 1};};
class MultiTypeStack
{
public:
template<typename T>
void push(const T &val){std::get<TypeIndex<T>::i>(stacks_).push(val);}
template<typename T>
void pop(){std::get<TypeIndex<T>::i>(stacks_).pop();}
template<typename T>
T top(){return std::get<TypeIndex<T>::i>(stacks_).top();}
private:
std::tuple<std::stack<int>, std::stack<double>> stacks_;
};
Create an std::unordered_map<std::type_index, std::unique_ptr<unknown>>
. Your typed access code takes the type and finds the appropiate entry. Then static_cast
the unknown
to a type dependent on T
that holds your stack.
Make sure unknown
is a base of stack_holder<T>
, and that unknown
has a virtual
destructor.
This is probably not exactly what you want, but the C++ type system is pure: later expressions cannot change 'earlier' types.
If you chained the type you could construct a more complex type, but this is just listing the types while concealing them.
If the object is a singleton some hackery using static
locals could work.
这篇关于仅使用静态多态性的异构容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!