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

如何在不增加类大小的前提下兼容构造初始化列表的条件宏?

问题描述

我有一套用于条件生成和初始化类成员的宏,代码如下:

#ifdef LIFETIME_TRACKING

#define DEFINE_TRACKER_MEMBER() mutable ::LifetimeTracker m_tracker
#define INITIALIZE_TRACKER_MEMBER(x) m_tracker(x)

#else

#define DEFINE_TRACKER_MEMBER() using dummy = void
#define INITIALIZE_TRACKER_MEMBER(x) /* ??? */ 

#endif

宏的使用方式示例:

struct Example
{
    int data;
    Dependency dep;
    DEFINE_TRACKER_MEMBER();

    Example() : data(42), INITIALIZE_TRACKER_MEMBER(dep) { }
};

当定义LIFETIME_TRACKING时一切正常,但未定义该宏时,我找不到既能让构造函数初始化列表里的, INITIALIZE_TRACKER_MEMBER(dep)语法通过编译,又不额外增大类体积、不破坏语法美观(比如把逗号放进宏里)的方法。

我曾尝试让DEFINE_TRACKER_MEMBER()创建一个空结构体成员:

#define DEFINE_TRACKER_MEMBER() struct { } m_tracker
#define INITIALIZE_TRACKER_MEMBER m_tracker{}

但这样会增加父类的体积,因此寻求更好的解决方案。

解决方案

方案1:C++20及以后(推荐)

利用C++20引入的[[no_unique_address]]属性,确保空成员不占用类的实例空间,同时保持原有语法完全不变:

#ifdef LIFETIME_TRACKING

#define DEFINE_TRACKER_MEMBER() mutable ::LifetimeTracker m_tracker
#define INITIALIZE_TRACKER_MEMBER(x) m_tracker(x)

#else

// 用[[no_unique_address]]修饰空结构体成员,编译器会优化掉其存储空间
#define DEFINE_TRACKER_MEMBER() [[no_unique_address]] struct {} m_tracker
#define INITIALIZE_TRACKER_MEMBER(x) m_tracker()

#endif
  • [[no_unique_address]]是标准属性,编译器会保证空成员不占用类实例的额外空间,完全符合需求。
  • 原有类定义和构造函数的语法无需任何修改。

方案2:兼容C++17及更早版本

如果需要兼容旧标准,可以利用空基类优化(EBO),调整宏定义让类继承一个空基类,同时保持构造函数语法不变:

#ifdef LIFETIME_TRACKING

// 定义跟踪成员,不修改类继承关系
#define TRACKED_STRUCT(struct_name) struct struct_name
#define DEFINE_TRACKER_MEMBER() mutable ::LifetimeTracker m_tracker
#define INITIALIZE_TRACKER_MEMBER(x) m_tracker(x)

#else

// 定义空基类,利用EBO不占用类空间
struct EmptyTracker {};
#define TRACKED_STRUCT(struct_name) struct struct_name : private EmptyTracker
#define DEFINE_TRACKER_MEMBER() /* 无成员定义 */
#define INITIALIZE_TRACKER_MEMBER(x) EmptyTracker()

#endif

使用时只需将原有的struct Example替换为TRACKED_STRUCT(Example):

TRACKED_STRUCT(Example)
{
    int data;
    Dependency dep;
    DEFINE_TRACKER_MEMBER();

    Example() : data(42), INITIALIZE_TRACKER_MEMBER(dep) { }
};
  • 空基类优化是C++标准允许的行为,所有主流编译器都支持,空基类不会增加类实例的体积。
  • 仅需修改类的定义方式,构造函数的初始化列表语法保持不变。

方案3:依赖编译器扩展(不推荐)

部分编译器(如GCC、Clang)在C++17及更早版本中,会自动优化掉类中非第一个的空成员(即使没有[[no_unique_address]])。这种情况下可以直接使用你最初的尝试,但这是非标准行为,兼容性无法保证:

#ifdef LIFETIME_TRACKING

#define DEFINE_TRACKER_MEMBER() mutable ::LifetimeTracker m_tracker
#define INITIALIZE_TRACKER_MEMBER(x) m_tracker(x)

#else

#define DEFINE_TRACKER_MEMBER() struct { } m_tracker
#define INITIALIZE_TRACKER_MEMBER(x) m_tracker()

#endif

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 15:17:02