为许多类型创建 "custom typeid" 并缓存它们的 sizeof()
Create "custom typeid" for many types AND cache their sizeof()
有很多类型的元素E0,E1,...
,它们都来自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()
?
它必须 return 正确的值 [#2] 稍后 "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 ............
}
如何实现?
要求:
- 不允许手动分配
E0,E1,E2,...
的 id 整数,因为可维护性低。
- 用户不必手动 "register"
E0,E1,E2,...
到 CCollection
。
当新类型的元素时,例如E1000,不用修改。
..... 即 CCollection
对于 E1000 应该是 "just work"。
- 最高性能,例如:-
- 应避免虚拟调用,除非完全无法避免。
- 尽可能使用
constexpr
。
- 函数内部的静态变量不好。
- 不要修改
E0,E1,E2,...
的代码
设计的灵活性
- 如果
CCollection
的函数从未被某个 E-X
、
调用
E-X
的管理可以省略(由您决定)。
- 只有 1 个 CCollection 实例。
clue1: 模板似乎是最有希望的路径,但我不确定。
clue2:(编辑)我计划的这个片段可能会有所帮助:-
template<class EX> int toId(EX* element){//[#1]
// register something?
}
如你所料,真正的问题远不止于此,
但这是我整个拼图中唯一缺少的拼图。
虽然我想要代码,但非常感谢您的指导。
我认为以下不会违反您的任何规则:
struct CCollection
{
template <typename T>
std::size_t toId() {
auto it = info.find(typeid(T));
if (it == info.end()) {
it = info.insert({typeid(T), {count++, sizeof(T)}}).first;
}
return it->second.id;
}
std::size_t sizeOf(const Base& base) const {
const auto& data = info.at(typeid(base));
return data.size;
}
std::size_t count = 0;
std::unordered_map<std::type_index, Data> info;
};
如果您可以在 Element
和每个 EX
之间添加一个中间 class,这是一个可能的解决方案(有一个最小的工作示例):
#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
的实例,就会出现示例代码中的问题。
不管怎样:
- 你说它永远不应该发生。
- 您可以强制使用该功能。
-
CCollection
class 被设计成 returns 从 sizeOf
0 如果你这样做的话。
也就是说,它至少可以作为更详细的生产代码的基础。
有很多类型的元素E0,E1,...
,它们都来自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()
?
它必须 return 正确的值 [#2] 稍后 "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 ............
}
如何实现?
要求:
- 不允许手动分配
E0,E1,E2,...
的 id 整数,因为可维护性低。 - 用户不必手动 "register"
E0,E1,E2,...
到CCollection
。
当新类型的元素时,例如E1000,不用修改。
..... 即CCollection
对于 E1000 应该是 "just work"。 - 最高性能,例如:-
- 应避免虚拟调用,除非完全无法避免。
- 尽可能使用
constexpr
。 - 函数内部的静态变量不好。
- 不要修改
E0,E1,E2,...
的代码
设计的灵活性
- 如果
CCollection
的函数从未被某个E-X
、
调用E-X
的管理可以省略(由您决定)。 - 只有 1 个 CCollection 实例。
clue1: 模板似乎是最有希望的路径,但我不确定。
clue2:(编辑)我计划的这个片段可能会有所帮助:-
template<class EX> int toId(EX* element){//[#1]
// register something?
}
如你所料,真正的问题远不止于此,
但这是我整个拼图中唯一缺少的拼图。
虽然我想要代码,但非常感谢您的指导。
我认为以下不会违反您的任何规则:
struct CCollection
{
template <typename T>
std::size_t toId() {
auto it = info.find(typeid(T));
if (it == info.end()) {
it = info.insert({typeid(T), {count++, sizeof(T)}}).first;
}
return it->second.id;
}
std::size_t sizeOf(const Base& base) const {
const auto& data = info.at(typeid(base));
return data.size;
}
std::size_t count = 0;
std::unordered_map<std::type_index, Data> info;
};
如果您可以在 Element
和每个 EX
之间添加一个中间 class,这是一个可能的解决方案(有一个最小的工作示例):
#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
的实例,就会出现示例代码中的问题。
不管怎样:
- 你说它永远不应该发生。
- 您可以强制使用该功能。
-
CCollection
class 被设计成 returns 从sizeOf
0 如果你这样做的话。
也就是说,它至少可以作为更详细的生产代码的基础。