c ++跨编译单元的增量类型ID

c++ incremental type ID across compilation units

我需要每个派生的 class 都有一个唯一的 ID,但 ID 需要是递增的。 这是我当前的实现:

//component.cpp
class ComponentId
{
public:
    ComponentId();


    static int nextId;
    int id;
};

template<class T>
class Component {
public:
    static const ComponentId componentId;
};

template<class T>
const ComponentId Component<T, chunkSize>::componentId;

///component.cpp
int ComponentId::nextId = 0;

ComponentId::ComponentId() : id(nextId++)
{
}

//IN static library a
struct compA : public Component<compA> {

}

//In static library b
struct compB : public Component<compB> {

}

//in main.cpp
#include <component.h>
#include <compA.h>
#include <compB.h>
std::cout << compA::componentId.id << std::endl;
std::cout << compB::componentId.id << std::endl;

这在我的所有单元测试中都运行良好,但在使用多个编译单元或跨静态库时似乎无法按预期运行。 ID 在不同的库中重复使用。一个库的 ID 可能为 0、1、2 和 3,但另一个库也将有 class 个 ID 为 0 和 1 的元素。 我的猜测是 nextid 字段没有被共享。

我也尝试过使用 extern 关键字,但它似乎产生了同样的问题。 我也曾尝试制作一个静态 getId 函数,希望在第一次使用时进行初始化,但没有这样的运气。

我确实需要 ID 为 'tight',如 1、2、3、4、5,而不是 67、80、123、1、4。

有什么想法吗?

假设您希望在多个 TU 之间共享一个 int 实例,我认为使用 inline 函数 returns 对 static int 的引用应该可以诀窍:

// counter.hpp
namespace detail 
{
    inline int& getCounter()
    {
        static int result{0};
        return result;
    }
}

inline int nextId()
{
    return detail::getCounter()++;
}

// component.cpp
ComponentId::ComponentId() : id(nextId())
{
}

然而,这感觉很脆弱并且容易出错,特别是如果您的目标是 serialization/deserialization 依赖您的 ID。如果您知道 compile-time 处的所有组件类型,我建议使用类型列表。例如

using components = typelist<
    Component0,
    Component1,
    Component2,
    Component3
>;

否则,如果您只知道 run-time 处的组件类型,请提供某种允许用户以受控方式 register/unregister 类型的注册表。