You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CMake编译下如何实现真正静态变量?解决类重复注册问题

问题描述

现有如下宏定义:

#define REGISTER_CLASS(CLASSNAME) struct CLASSNAME; \
    static bool CLASSNAME##registered = \
    (\
        (Register<CLASSNAME>()), \
        true \
    );

在类定义前使用该宏时,类可通过Register函数完成注册。但存在继承场景时,例如:

// 文件1
REGISTER_CLASS(Foo)
class Foo
{
    // ...
};

// 文件2
REGISTER_CLASS(FooBar1)
class FooBar1: public Foo 
{
    // ...
};

// 文件3
REGISTER_CLASS(FooBar2)
class FooBar2: public Foo 
{
    // ...
};

尽管Fooregistered是静态变量,但在CMake编译环境下,Foo类仍会被多次注册。而不使用CMake编译时,代码行为正常。需要解决CMake环境下的重复注册问题,实现真正的单次静态变量初始化。

解决方法

方案1:使用C++17 inline静态变量

修改宏定义,将静态变量声明为inline,C++17标准规定多个编译单元中的同名inline静态变量会被合并为单一实例,确保Register<Foo>()仅执行一次:

#define REGISTER_CLASS(CLASSNAME) struct CLASSNAME; \
    inline static bool CLASSNAME##registered = \
    (\
        (Register<CLASSNAME>()), \
        true \
    );

这是最简洁且符合现代C标准的解决方案,前提是项目支持C17及以上版本。

方案2:利用模板静态成员的单例特性

模板的静态成员在整个程序生命周期中只会实例化一次,可将注册逻辑封装到模板中:

// 定义通用注册模板
template<typename T>
class Registrar {
public:
    static const bool registered;
};

template<typename T>
const bool Registrar<T>::registered = (Register<T>(), true);

// 修改宏定义
#define REGISTER_CLASS(CLASSNAME) struct CLASSNAME; \
    static const auto& CLASSNAME##registrar = Registrar<CLASSNAME>::registered;

无论多少个编译单元引用Registrar<Foo>::registered,该静态成员只会初始化一次,从根源避免重复注册。此方案兼容C++11及以上版本。

方案3:在Register函数内部做去重校验

如果无法修改宏的结构,可在Register函数中添加全局的注册记录,检查当前类是否已经注册过:

#include <unordered_set>
#include <typeinfo>

std::unordered_set<const std::type_info*> registered_classes;

template<typename T>
void Register() {
    const auto& type = typeid(T);
    if (registered_classes.find(&type) == registered_classes.end()) {
        // 执行实际的注册逻辑
        // ...
        registered_classes.insert(&type);
    }
}

这种方式不依赖编译选项或C++版本,通过运行时判断避免重复注册,缺点是会引入少量运行时开销。

方案4:调整CMake编译选项(不推荐)

CMake默认可能为GCC等编译器开启-fno-common选项,该选项会让每个编译单元中的全局静态变量生成独立实例。可在CMakeLists.txt中添加编译选项关闭该特性:

add_compile_options(-fcommon)

此方案依赖编译器特定行为,兼容性差,仅作为临时 workaround 使用。

内容的提问来源于stack exchange,提问作者ingotangjingle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 19:03:27