我有一个可以通过网络发送的类型列表,举个例子:
enum types {
    E_T1,
    E_T2,
    E_T3,
    E_T4
};
现在我有对应于每种类型的类的列表,让我们说每一个被声明为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)
这个问题是每个默认情况下每个变体限制为20个条目.这可以被覆盖,但从我所理解的应该考虑每种类型的开销,我们在这里谈论几千种类型.
还尝试了boost.any,但它没有任何类型信息,所以再次出了问题.有谁有任何好的想法如何才能优雅地解决这个问题?寻找我无需在任何时候处理类型的情况下编写1k开关语句的东西.
所有类型都以编译类型命名,相应的ID也是如此.Id - >类型解析需要在运行时发生.
谢谢,罗宾.
外部多态性(*)
它是一个广为人知的习语,但它被广泛使用:我在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>());
}
因此,这是添加新级别间接的经典策略.
现在,你显然做需要一个开关从价值转移到类.或许......一张地图?
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)();
 }
现在你可以多态地处理它们了:
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);
}
当然,欢迎您根据自己的需要制定相应的策略.例如,移出地图,select以便您可以动态注册您的类型(例如插件).
(*)至少这是我的名字,我很高兴发现它已被命名.