C++如何编译期检查派生类向上转型到基类是否需要指针调整
编译期判断向上转型是否需要指针调整的实现方案
结论
可以实现,非虚继承场景下基类子对象的偏移是编译期常量,仅需判断该偏移是否为0即可。虚继承场景下基类偏移量运行时动态确定,无法编译期获取。
你示例中Clang能判定printf的输出结果,本质就是编译器在编译期就确定了基类偏移量是常量,我们的实现就是直接提取这个编译器已知的常量值。
实现方案
方案1:C++20 标准无扩展实现
仅要求C++20及以上标准,无编译器依赖,适用标准布局类型:
#include <type_traits> template <typename Derived, typename Base> requires std::is_base_of_v<Base, Derived> && std::is_standard_layout_v<Derived> struct needs_upcast_adjustment { static constexpr bool value = []() consteval { Derived d{}; const Derived* pd = &d; const Base* pb = pd; return reinterpret_cast<const char*>(pb) != reinterpret_cast<const char*>(pd); }(); }; template <typename Derived, typename Base> constexpr bool needs_upcast_adjustment_v = needs_upcast_adjustment<Derived, Base>::value;
方案2:编译器扩展实现(兼容C++11及以上)
主流编译器均提供内置扩展可直接获取基类子对象偏移,不受标准布局限制:
- GCC/Clang 环境:
template <typename Derived, typename Base> constexpr bool needs_upcast_adjustment_v = __builtin_offsetof(Derived, Base) != 0;
- MSVC 环境:
template <typename Derived, typename Base> constexpr bool needs_upcast_adjustment_v = __offsetof_base(Derived, Base) != 0;
测试验证
用你给出的示例类验证,静态断言可直接编译期通过:
struct A { int a; }; struct B { int b; }; struct C : A, B { int c; }; // 验证C转A不需要调整 static_assert(!needs_upcast_adjustment_v<C, A>); // 验证C转B需要调整 static_assert(needs_upcast_adjustment_v<C, B>);
内容的提问来源于stack exchange,提问作者dragonroot
相关产品推荐
相关产品推荐

