运行时值到类型映射

Rob*_*bin 4 c++ networking

我有一个可以通过网络发送的类型列表,举个例子:

enum types {
    E_T1,
    E_T2,
    E_T3,
    E_T4
};
Run Code Online (Sandbox Code Playgroud)

现在我有对应于每种类型的类的列表,让我们说每一个被声明为class E_T1 {...},class E_T2 {...}等等.

它们不是来自共同的基类,也不可能这样做.每个类都有一个验证方法,我需要通过网络发送数据来调用.客户端发送数据D和ID对应于消息类型.我需要掌握与该类型对应的对象.如果需要,我可以使用C++ 0x功能.

到目前为止我所尝试的是使用专门的模板types,为与之相关的对象保存一个typedef.这显然是一个愚蠢的想法,因为模板参数需要编译时间常数,因此getType<data.id()>::type无法做一些事情.

然后我尝试使用Boost.Variant来获得这样的常见可返回类型(使用mpl向量来迭代runntime上的已注册类型以进行重新布局):

template <typename C>
struct getType() {
    typedef C type;
}

typedef boost::mpl::vector<
    getType<E_T1>,
    getType<E_T2>,
    getType<E_TX>...
> _types;

typedef boost::make_variant_over<_types>::type _type;

//use a map to store each type <-> id
boost::unorderd_map<types, _type> m;
m[E_T1] = getType<E_T1>();

m[data.id()]::type x; //<- access type, can now call x.validate(data)
Run Code Online (Sandbox Code Playgroud)

这个问题是每个默认情况下每个变体限制为20个条目.这可以被覆盖,但从我所理解的应该考虑每种类型的开销,我们在这里谈论几千种类型.

还尝试了boost.any,但它没有任何类型信息,所以再次出了问题.有谁有任何好的想法如何才能优雅地解决这个问题?寻找我无需在任何时候处理类型的情况下编写1k开关语句的东西.

所有类型都以编译类型命名,相应的ID也是如此.Id - >类型解析需要在运行时发生.

谢谢,罗宾.

Mat*_* M. 6

外部多态性(*)

它是一个广为人知的习语,但它被广泛使用:我在shared_ptr实现中首次遇到它,它在我的工具箱中非常有用.

我们的想法是为所有这些类型创建一个基类.但没有让他们直接从中衍生出来.

class Holder {
public:
    virtual ~Holder() {}

    virtual void verify(unsigned char const* bytes, size_t size) const = 0;

}; // class Holder

template <typename T>
class HolderT: public Holder {
public:
     HolderT(): _t() {}

     virtual void verify(unsigned char const* bytes, size_t size) const {
         _t.verify();
     }

private:
    T _t;
}; // class HolderT

template <typename T>
std::unique_ptr<Holder> make_holder() {
    return std::unique_ptr<Holder>(new HolderT<T>());
}
Run Code Online (Sandbox Code Playgroud)

因此,这是添加新级别间接的经典策略.

现在,你显然需要一个开关从价值转移到类.或许......一张地图?

using maker = std::unique_ptr<Holder> (&)();
using maker_map = std::unordered_map<types, maker>;

std::unique_ptr<Holder> select(types const E) {
    static maker_map mm;
    if (mm.empty()) {
        mm.insert(std::make_pair(E_T1, make_holder<EC_T1>));
        // ...
    }

    maker_map::const_iterator it = mm.find(E);

    if (it == mm.end()) { return std::unique_ptr<Holder>(); }

    return (*it->second)();
 }
Run Code Online (Sandbox Code Playgroud)

现在你可以多态地处理它们了:

void verify(types const E, unsigned char const* bytes, size_t size) {
    std::unique_ptr<Holder> holder = select(E);
    if (not holder) { std::cerr << "Unknown type " << (int)E << "\n"; return; }

    holder->verify(bytes, size);
}
Run Code Online (Sandbox Code Playgroud)

当然,欢迎您根据自己的需要制定相应的策略.例如,移出地图,select以便您可以动态注册您的类型(例如插件).

(*)至少这是我的名字,我很高兴发现它已被命名.