重新解释cast void而不使用类型标识符

时间:2016-08-06 00:18:24

标签: c++ c++11 templates casting type-erasure

我使用类型擦除(void cast)在一对一地图中存储多个基本类型(float,bool,int等)。重新解释原始数据类型的一种方法是使用pair / union / class来存储具有类型标识符(例如,对)的值。在没有Boost的情况下使用C ++ 11解决没有标识符的基本类型是否有一种干净的方法?

std::map<int, void *> m_mymap;
// avoid std::map<int, pair<void, MyEnum> > m_mymap;

template <class T> void setValue<T>(int i_key, T i_val)
{
    m_mymap[i_key] = reinterprete_cast<void *>(i_val);
}

template <class T> T getValue<T>(int i_key)
{
    return reinterprete_cast<T>(i_val);
}

doSomeWork()
{
    for (const auto & elem : m_mymap)
    {
        auto val = some_magical_cast< ??? >(elem.second) // resolve type without a nasty switch against MyEnum 
        // do some work
    }
}

编辑:更新问题以使用void *

2 个答案:

答案 0 :(得分:3)

auto val = some_magical_cast< ??? >(elem.second) // resolve type without a nasty switch against MyEnum 

C ++是一种静态类型语言。必须在编译时知道每种类型。您尝试做的事情将要求根据放入地图的内容在运行时确定类型。

用C ++中的任何东西都不可能。 val必须具有单个特定类型,而不是通过执行运行时代码确定的类型。循环的每次迭代都必须赋予它相同的类型。 union或variant允许您存储在运行时确定的几种类型之一。但是它们存储的类型集在编译时是固定的。

即使auto val可能以某种方式导致一系列不同的类型,void*也不包含任何可用于恢复其指向的类型的信息。请注意,boost/std::any也缺乏恢复此类型的能力;你必须要求一个特定的类型(不同的是,如果你要求错误的类型,any将失败,而void*将给你UB)。

所以不,这是不可能的。

答案 1 :(得分:2)

正如@NicolBolas正确解释的那样,你不能。

作为一种可行的方法/解决方法,您可以使用基于双重调度理念的技术,如下例所示:

#include<map>
#include<utility>
#include<iostream>

class C {
public:
    template<typename T>
    void accept(int k, T v) { std::cout << k << " " << v << std::endl; }
};

using P = void(*)(C &, int, void *);

std::map<int, std::pair<P, void*>> m;

template<typename T>
void proto(C &c, int k, void *v) {
    c.accept(k, *static_cast<T*>(v));
}

template <class T>
void set(int k, T *v) {
    m[k] = { &proto<T>, v };
}

void get(C &c, int k) {
    auto p = m[k];
    p.first(c, k, p.second);
}

int main() {
    int i = 42;
    double d = 1.2;

    set(0, &i);
    set(1, &d);

    C c;
    for(auto &&k: m) {
        get(c, k.first);
    }
}

它需要一个额外的类(示例中为C) 您可以为该类添加不同类型的不同方法(例如,您可以使用两种接受intdouble的方法代替模板方法。 这样,您可以拥有广义行为以及许多特定类型的行为。

当然,它更复杂而且不是免费的,但是否则你无法获得你想要的东西。