仅使用静态多态性的异构容器 [英] Heterogenous container using only static polymorphism

查看:71
本文介绍了仅使用静态多态性的异构容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的目标是实现一个容器(这里是一组堆栈,每种类型一个),该容器同时接受许多不同类型的对象.使用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的类型,该类型保存您的堆栈.

确保unknownstack_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆