如何将C++类/结构体成员偏移量设为constexpr?
用constexpr编译期获取类成员偏移量的实现方法
原代码通过运行时操作成员指针的内部表示来获取类成员偏移:
struct Base { virtual ~Base() = default; }; struct Cls : public virtual Base { int a, b; }; int main() { int Cls::* ptr = &Cls::a; unsigned long offset = *reinterpret_cast<unsigned long*>(&ptr); }
由于类布局在编译期就已固定,我们可以将偏移量的计算改为constexpr编译期完成,避免运行时开销。原方法依赖左值且涉及未定义行为(直接reinterpret_cast成员指针),以下是符合标准的constexpr实现方案:
编译期计算成员偏移的constexpr模板函数
#include <cstddef> struct Base { virtual ~Base() = default; }; struct Cls : public virtual Base { int a, b; }; template <typename Class, typename Member> constexpr std::size_t member_offset(Member Class::* member_ptr) noexcept { // 利用编译期空对象的地址差计算偏移 const Class* const obj = nullptr; const char* member_addr = reinterpret_cast<const char*>(&(obj->*member_ptr)); const char* obj_addr = reinterpret_cast<const char*>(obj); return static_cast<std::size_t>(member_addr - obj_addr); } // 编译期直接计算得到偏移量 constexpr std::size_t offset_a = member_offset(&Cls::a); constexpr std::size_t offset_b = member_offset(&Cls::b); int main() { // 编译期验证偏移值(具体数值取决于编译器的类布局) static_assert(offset_a == 16); static_assert(offset_b == 20); }
方案说明
- 标准合规性:避免了直接解析成员指针内部表示的未定义行为,通过编译期地址差计算偏移,符合C++17及以后的标准。
- 编译期计算:
constexpr函数在编译阶段完成计算,offset_a和offset_b是编译期常量,可用于需要编译期常量的场景(如数组大小、模板参数)。 - 适配虚继承:对于虚继承的类,编译器会自动处理
this指针的调整,该函数能正确计算成员相对于类对象起始地址的偏移。
内容的提问来源于stack exchange,提问作者AxD
相关产品推荐
相关产品推荐

