将类型映射到整数值后,如何在给定整数值的情况下取回类型?

Posted

技术标签:

【中文标题】将类型映射到整数值后,如何在给定整数值的情况下取回类型?【英文标题】:After mapping a type to an integral value, how do I get the type back given an integral value? 【发布时间】:2019-12-06 14:03:47 【问题描述】:

我正在尝试构建这个实体组件系统,我有这个模板化的容器类,用于存储所有组件类型,并且对于每个传递的类型,下面的代码负责将类型映射到索引,以便我可以将它用作 std::map 的键(其中值是指向“向量”的指针)。因此,例如调用 typeId<RectComponent>() 可能会返回值 2,假设 typeId 类之前使用其他模板参数实例化了 2 次:

#pragma once
using uInt = size_t;

class typeIdBase

private:
    static uInt internal_generateTypeID() 
        static uInt typeIDCounter;
        return typeIDCounter++;
        template<typename T> friend class typeId;
;

template<typename T>
class typeId 
public:
    operator uInt() const  return id; 
private:
    static inline uInt id = typeIdBase::internal_generateTypeID();
;

问题是现在我还需要走相反的方向,我需要一个返回给定 size_t 值的类型,所以例如在我的代码中typename idType&lt;2&gt;::type应该相当于键入RectComponent。 按照上面与值 2 关联的 RectComponent 的示例,typeId&lt;typename idType&lt;2&gt;::type&gt;() 也应该返回 2,只是为了清楚起见。 我被卡住了,不知道如何到达那里,有什么建议吗?

【问题讨论】:

我认为不是这个把戏。您需要在某处写出所有类型和数字。或者制作一个脚本来生成它们。 【参考方案1】:

就在你这样做的时候

typeId<typename idType<2>::type>()

您要求编译器使用在编译时未知的模板参数值来实例化模板。而这在 C++ 中是行不通的。模板只是编译器的代码蓝图,对于它们实例化的每组不同的参数,都有一个模板化代码版本,其中包含在翻译单元中实际编译的具体类型。在运行时,这些模板都不存在,您只有不同的实例化版本,仅此而已。

所以这种类型的实现是行不通的。根据您的实际问题,您必须在编译时提供这样的映射,或者找到替代解决方案。

【讨论】:

【参考方案2】:

您应该非常小心使用示例中的静态初始化程序,因为给定类型的 id 可能会在编译期间发生变化。

不幸的是,没有办法将索引映射回类型 - 正如@user253751 已经评论的那样。

因为您说要使用索引作为地图的键,所以我建议改用type_index

这允许您将类型直接用作地图的键。 如果您想为给定类型存储一组小部件,您可以使用以下内容:

Live Demo for Testing

#include <iostream>
#include <memory>
#include <typeindex>
#include <vector>
#include <map>
#include <string>

class WidgetMap 
public:
  template<typename T>
  void addWidget(const T& val) 
    auto idx = std::type_index(typeid(T));
    if(m_map.find(idx) == m_map.end())
      m_map[idx] = std::make_shared<std::vector<T>>();

    auto vecPtr = std::static_pointer_cast<std::vector<T>>(m_map[idx]);
    vecPtr->push_back(val);
  

  template<typename T>
  std::shared_ptr<std::vector<T>> getWidgets() 
    auto idx = std::type_index(typeid(T));
    auto it = m_map.find(idx);
    if(it == m_map.end())
      throw std::runtime_error(std::string"No widget stored for type " + typeid(T).name());

    return std::static_pointer_cast<std::vector<T>>(it->second);
  

private:
  std::map<std::type_index, std::shared_ptr<void>> m_map;
;

然后您可以使用您的小部件类型作为键:

struct ExampleWidget 
  std::string message;
;


// Usage:
WidgetMap m;

// Add widgets    
m.addWidget(ExampleWidget"Hello");
m.addWidget(ExampleWidget"World");

// retrieve widgets by type
auto exampleWidgets = m.getWidgets<ExampleWidget>();
for(auto& val : *exampleWidgets)
  std::cout << val.message << std::endl;

【讨论】:

我的代码已经可以做到这一点,我可以做到getVector&lt;RectComponent&gt;() 并得到一个向量,在这个相应的例子中我需要的是一个std::type_index 它应该给我一个相应的类型。因为如果您想象一个带有std::map&lt;std::type_index, size_t&gt; componentsId 的实体,它只存储组件的 id,当然我希望能够在需要时访问特定的组件,但是在销毁时我想要一个循环范围,该映射可以将 type_index 转换为正确的类型,以便访问正确的向量并删除组件。

以上是关于将类型映射到整数值后,如何在给定整数值的情况下取回类型?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 max() 或对其进行迭代的情况下找到堆栈中的最大整数值?

N12-数值的整次方

如何在 BlackBerry 表中显示整数值

如何在 EditText 中添加整数值?

one-hot vector 是啥意思

如何将整数值分配给字符串并在 SQL 中找到总和