类型的备用ID生成器 [英] Alternative id generators for types

查看:76
本文介绍了类型的备用ID生成器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的一个项目中,我有一个 ID生成器,其类型类似于:

In a project of mine, I have an ID generator for types that looks similar to this:

class Family {
    static std::size_t identifier;

    template<typename...>
    static std::size_t family() {
        static const std::size_t value = identifier++;
        return value;
    }

public:
    template<typename... Type>
    inline static std::size_t type() {
        return family<std::decay_t<Type>...>();
    }
};

std::size_t Family::identifier{};

用法:

const auto id = Family::type<FooBar>();

对于我来说,它可以正常工作,但有一些限制。最令人讨厌的一个问题(该问题的目的)是,如果链接共享库的所有可执行文件都尝试创建标识符,则该可执行文件将无法使用该链接。结果通常是将第n个标识符跨边界分配给不同的类型,因为每个共享库都维护自己的独立 Family :: identifier

It works just fine for my purposes, but it has some limitations. The most annoying one (purpose of the question) is that it fails when used by an executable that links to shared libraries if all of them try to create identifiers. The result is usually that the n-th identifier is assigned to different types across boundaries because each shared library maintains their own separate Family::identifier.

一些共享库专家指出了一种更可靠的解决方案,值得赞赏,但未能提出一个不会破坏性能的解决方案(几乎所有人都引入了容器,找到功能和内存分配。)

Some shared library guys pointed out that a more reliable solution would be appreciated, but failed to suggest one that didn't ruin the performance (almost all of them introduce containers, find functionalities and memory allocation).

有没有其他方法可以解决上述限制而又不损失当前设计的性能?

Is there any alternative approach that works around the aforementioned limitations without losing the performance of the current design?

我搜索了SO,发现了一些有趣的答案。其中许多已经有好几年了。只要现有类的接口保持完整,我想探索的是最新标准修订版的解决方案。

这个是最有趣的一个。它使用静态成员的地址来实现相同的目的,但不符合顺序生成标识符的想法

I searched through SO and found some interesting answers. Many of which were several years old. I'd like to explore solutions up to the latest revision of the standard instead, as long as the interface of the existing class remains intact.
This one is the most interesting one. It uses addresses of static members to achieve the same, but it doesn't fit with the idea of sequentially generated identifiers

注意:使用RTTI

注意:必须按照上面介绍的解决方案顺序生成ID,并且ID必须从0开始。

Note : ids must be generated sequentially and starting from 0 as in the solution presented above.

推荐答案

出现问题是因为您的头文件中包含以下行:

Your problem occurs because you have this line in your header file:

std::size_t Family::identifier{};

因此,它最终出现在每个翻译单元中。取而代之的是,您需要为此将存储移动到.cpp源文件,该文件仅编译一次,或者编译到其自己的共享库中。然后,程序中将只有一个 identifier 实例,它将按您的预期工作。

It therefore ends up in each translation unit. Instead, you need to move the storage for this to a .cpp source file which is compiled only once, perhaps into a shared library of its own. Then there will be just one instance of identifier in a program, and it will work as you intend.

您也可以将标识符从类 static 变量移动到全局 extern 在头文件中(和上面一样,在一个.cpp文件中定义)。

You could also move identifier from being a class static variable to a global extern one in the header file (and as above, define it in a single .cpp file).

如果您使用的是C ++ 17或更高版本,则可以也可以尝试:

If you have C++17 or later, you can also try:

inline std::size_t Family::identifier{};

虽然该语言不能保证(甚至无法提及)跨共享使用此新功能会发生什么库边界,它确实可以在我的计算机上工作。

While the language does not guarantee (or even mention) what happens when you use this new feature across shared libraries boundaries, it does work on my machine.

这篇关于类型的备用ID生成器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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