创建“自定义类型ID";对于许多类型并缓存其sizeof() [英] Create "custom typeid" for many types AND cache their sizeof()

查看:192
本文介绍了创建“自定义类型ID";对于许多类型并缓存其sizeof()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

元素E0,E1,...的类型很多,都是从Element派生的.

There are many type of elements E0,E1,..., all of them derived from Element.

class Element{  public: int id=0; } //"Element" can be edited
class E0: public Element{ ... }
class E1: public Element{ ... }
...
class E999: public Element{ ... }

如何为E0,E1,...缓存sizeof()?
以后必须通过自定义typeid" [#1]返回正确的值[#2].

How to cache sizeof() for E0,E1,...?
It has to return the correct value [#2] later by "custom typeid" [#1].

class CCollection{
    template<class EX> EX* create(){ //(Edit)
        //all EX* is created by this function
    }
    /** user only pass EX*, never pass Element* */  (Edit)
    int toId(Element* element){//[#1] should replaced by template?
          //....... return id, e.g. 0 for E0, 1 for E2, 2 for E1, ...  
          // can be in any order, but must unique and packed ........ 
    }
    int sizeOf(int id){//[#2]
        //....... return size of EX
        // must consistent with toId() ,
        // e.g. sizeof(E0) for 0, sizeof(E2) for 1, sizeof(E1) for 2 ........ 
    }
    //....... other fields / functions, if necessary ............


}

如何实现呢?

  1. 由于可维护性较低,不允许手动分配E0,E1,E2,...的id整数.
  2. 用户不必手动将"E0,E1,E2,..."注册到CCollection.
    如果是新类型的元素,例如E1000,无需进行任何修改.
    .....即CCollection对于E1000应该是正常工作".
  3. 最高性能,例如:-
    • 应避免虚拟调用,除非完全不可避免.
    • 如有可能,请使用constexpr.
    • 函数内部的静态变量不好.
  1. Manually assign id-integer of E0,E1,E2,... is not allowed, because of low maintainability.
  2. User doesn't have to "register" E0,E1,E2,... to CCollection manually.
    When new type of Element, e.g. E1000, no modification have to be done.
    ..... i.e. CCollection should be "just work" for E1000.
  3. Highest performance, e.g. :-
    • Virtual calling should be avoided, except totally unavoidable.
    • Use constexpr if possible.
    • Static variable inside a function is not good.

设计的灵活性

  1. 如果某个特定的E-X从未调用过CCollection的函数,则
    E-X的管理可以省略(由您决定).
  2. 只有1个CCollection实例.
  1. If CCollection's functions are never called for a certain E-X,
    the management for E-X can be omitted (up to you).
  2. There is only 1 CCollection instance.

线索1:模板似乎是最有前途的途径,但我不确定.

clue1: Template seems to be the most promising path, but I am not sure.

线索2:(编辑)我计划的这段代码可能会有所帮助:-

clue2: (Edit) This snippet I have planed may help :-

template<class EX> int toId(EX* element){//[#1] 
    // register something?
}

您可以猜到,真正的问题远不止于此,
但这是我整个难题中唯一缺失的拼图.

As you can guess, the real problem is far bigger than this,
but this is the only one missing jigsaw of my whole puzzle.

尽管我希望获得代码,但真的很感谢指南.

Although I wish for code, just a guide is really appreciated.

推荐答案

如果您可以在Element和每个EX之间添加一个中间类,这是一个可行的解决方案(带有一个最小的有效示例):

If you can add an intermediate class between Element and each EX, here is a possible solution (with a minimal, working example):

#include<cstddef>
#include<memory>
#include<vector>
#include<cassert>

struct Element {
    static std::size_t counter;
};

std::size_t Element::counter = 0;

template<typename>
struct ElementType: Element {
    static const int type;
};

template<typename T>
const int ElementType<T>::type = Element::counter++;

struct E0: ElementType<E0> {};
struct E1: ElementType<E1> { int i; };
struct E2: ElementType<E2> {};

class CCollection {
    void ensure(std::size_t type) {
        if(!(type < sizes.size())) {
            sizes.resize(type+1, 0);
        }
    }

    template<typename EX>
    void ensure() {
        ensure(EX::type);
        sizes[EX::type] = sizeof(EX);
    }

public:
    template<class EX>
    std::shared_ptr<EX> create() {
        ensure<EX>();
        return std::make_shared<EX>();
    }

    template<typename EX>
    std::size_t toId() {
        ensure<EX>();
        return EX::type;
    }

    std::size_t sizeOf(std::size_t type) {
        ensure(type);
        return sizes[type];
    }

private:
    std::vector<std::size_t> sizes;
};

int main() {
    CCollection coll;
    assert(coll.toId<E0>() != coll.toId<E1>());
    assert(coll.toId<E0>() != coll.toId<E2>());
    assert(coll.toId<E1>() != coll.toId<E2>());
    assert(coll.sizeOf(0) == sizeof(E0));
    assert(coll.sizeOf(1) == sizeof(E1));
    assert(coll.sizeOf(2) == sizeof(E2));
    assert(coll.sizeOf(0) != coll.sizeOf(1));
    // ...
}

如果不使用create尝试创建EX的实例,则会出现示例代码中的问题.
无论如何:

The problem in the code in the example arises if one tries to create instances of EX without using create.
Anyway:

  • 您说过它永远不会发生.
  • 您可以强制使用该功能.
  • CCollection类的设计目的是,如果您这样做,它将从sizeOf返回0.
  • You said it should never happen.
  • You can enforce the use of that function.
  • The CCollection class is designed so as it returns 0 from sizeOf if you do that.

也就是说,它至少可以作为更详细的生产代码的基础.

That said, it can serve as a base for a more elaborated production code at least.

这篇关于创建“自定义类型ID";对于许多类型并缓存其sizeof()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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