Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在运行时将ID解析为派生类型_C++_Template Meta Programming - Fatal编程技术网

C++ 在运行时将ID解析为派生类型

C++ 在运行时将ID解析为派生类型,c++,template-meta-programming,C++,Template Meta Programming,假设我有100个从Base派生的类。每个派生类在[0100]之间都有一个唯一的标识符,在编译时已知 我有一个接受ID的函数,需要返回一个新分配的具有该ID的派生类实例 Base* CreateDerived(uint32_t id) { return new Derived...(); } 每个ID都有一个巨大的开关盒显然不是一个好的解决方案。下面提供了一个我能想到的最佳解决方案的示例,但我觉得有一种方法可以做到这一点,而不需要vtable带来的开销 struct Registered

假设我有100个从Base派生的类。每个派生类在[0100]之间都有一个唯一的标识符,在编译时已知

我有一个接受ID的函数,需要返回一个新分配的具有该ID的派生类实例

Base* CreateDerived(uint32_t id) {
    return new Derived...();
}
每个ID都有一个巨大的开关盒显然不是一个好的解决方案。下面提供了一个我能想到的最佳解决方案的示例,但我觉得有一种方法可以做到这一点,而不需要vtable带来的开销

struct RegisteredClass {
    static RegisteredClass* ClassTable[MAX_DERIVED_CLASSES];
    static Base* CreateDerived(int ID) { return ClassTable[ID]->Create(); }

    RegisteredClass(int ID) { ClassTable[ID] = this; }
    virtual Base* Create() = 0;
};

template<typename T, int ID>
struct Register : RegisteredClass {
    Register() : RegisteredClass(ID) { }
    virtual Base* Create() { return new T; }
};

class Derived34 : Base {
    static Register<Derived34, 34> _register;
};
struct RegisteredClass{
静态RegisteredClass*类表[最大派生类];
静态基*CreateDerived(intid){return ClassTable[ID]->Create();}
RegisteredClass(int-ID){ClassTable[ID]=this;}
虚拟基*Create()=0;
};
模板
结构寄存器:RegisteredClass{
Register():RegisteredClass(ID){}
虚拟基*Create(){return new T;}
};
第34类:基本类{
静态寄存器_寄存器;
};
我是不是很傻,或者有没有其他不需要太多空间的方法

显然,为每一个设备配备一个巨大的开关箱并不是一个好的解决方案 身份证

这实际上是抽象工厂模式,正如您所描述的,它被广泛使用。我会坚持使用它,因为大多数程序员都很熟悉它


您的变体似乎过于复杂,难以维护。

在这种情况下,旧的易变宏功能可以简化任务并消除一些错误

#define CASE(n) case n: return new Derived##n

Base* CreateDerived(uint32_t id)
{
    switch(id)
    {
        CASE(1);
        CASE(2);
        CASE(3);
        // ...
        default:
            throw std::logic_error("Unhandled Derived## case");
    }
}

#undef CASE

除非它能完全由模板生成,否则交换机将很难维护,我甚至不会考虑它。对我所做的最正确的解决方案是脚本系统,而不是硬编码对象,但此时不可能。@ Duffic为什么开关难以维护?所有100种类型都必须手动添加。如果我要添加更多的派生类型,我必须记住将它们添加到开关中,而且它可能会被广泛使用,但如果我有100种不同的情况,比如dauphic,我不会使用它。我认为这是一个可接受的解决方案,除了边界/ID的硬编码和访问类表时缺少范围检查。是的,我省略了我确实认为这种方法是可以接受的,但我想知道是否有另一种解决方案(可能使用MPL)存在。您可以派生每个类的唯一标识符,例如,使用boost::uuid而不是硬编码的ID,并使用std::map或类似的方法而不是数组。但请注意,这将对性能产生影响。您确定vtables的空间开销有这么大的问题吗?假设32位操作系统(64位操作系统加倍),每个vtable需要4个字节,ClassTable为每个RegisteredClass添加4个字节,如果您创建一个RegisteredClass池,则每个RegisteredClass不需要超过8或16个字节(取决于对齐方式)。这使得每个类型(数据段和堆)最多24个字节,这意味着小于2.5 KB。对于64位操作系统,它可以达到5 KB。即使在大多数嵌入式系统上,我也知道这是相当合理的。这不是问题。我确实有内存限制,但并不严重。我主要只是好奇其他方法。