如何简化含基类成员指针的模板,适配C++14侵入式容器
问题背景
我正在实现一款侵入式容器(Boost.Intrusive无法满足我的特定需求),需适配C14标准(C17尚未普及),遇到如下问题:
现有代码结构
Hook类(存储链接信息)
struct Hook { void* next; };
容器类(以链表为例)
template< typename T, Hook T::*hook > struct Container { T* first = nullptr; void push_front( T& value ) { (value.*hook).next = first; first = &value; } };
基类与派生类(支持多维度索引)
template< typename Traits > struct Base { Hook by_time; Hook by_size; void check_inventory() {...} }; struct Derived : Base<ConcreteTraits> { };
编译错误场景
当尝试直接声明容器时:
Container< Derived, &Derived::by_time > inventory;
触发编译错误:
error: conversion from 'Hook Base
::' to 'Hook Derived::' is not allowed in a converted constant expression
31 | Container< Derived, &Derived::by_time> ca; ^~~~~~~~
当前繁琐 workaround
通过增加模板参数间接性实现,但需要暴露内部的Base类,且使用起来很麻烦:
template< typename T, typename U, Hook U::*hook > struct Container { };
声明方式:
Container< Derived, Base<ConcreteTraits>, &Derived::by_time> ca;
需求:如何修改框架,支持直接以Container< Derived, &Derived::by_time > ca;声明容器?
解决方案
在C++14中,可以借助模板参数推导和成员指针的隐式转换特性,通过引入辅助模板封装成员指针,让容器自动推导基类类型,既不用暴露Base类,又能简化声明。
步骤1:定义Hook封装模板与辅助推导函数
// 封装成员指针及其所属类型的模板 template<typename U, Hook U::*HookPtr> struct HookWrapper { using OwnerType = U; static constexpr Hook U::*value = HookPtr; }; // 辅助函数,用于自动推导HookWrapper的模板参数 template<typename U, Hook U::*HookPtr> constexpr HookWrapper<U, HookPtr> wrap_hook(Hook U::* /* unused */) { return {}; }
步骤2:修改Container模板
让容器接受HookWrapper作为参数,从其中获取成员指针的真实所属类型:
template<typename T, typename HookWrap> struct Container { static constexpr auto hook = HookWrap::value; T* first = nullptr; void push_front(T& value) { // 将Derived对象转换为成员指针所属的基类类型 auto& base_obj = static_cast<typename HookWrap::OwnerType&>(value); (base_obj.*hook).next = first; first = &value; } };
步骤3:简化容器声明
利用decltype推导HookWrapper的类型,无需手动指定Base类:
Container<Derived, decltype(wrap_hook(&Derived::by_time))> inventory;
进一步简化(可选宏封装)
如果觉得decltype(wrap_hook(...))还是繁琐,可以用宏封装:
#define MAKE_CONTAINER(T, HOOK) Container<T, decltype(wrap_hook(HOOK))>
使用方式:
MAKE_CONTAINER(Derived, &Derived::by_time) inventory;
原理说明
wrap_hook函数会自动识别&Derived::by_time的实际所属类型是Base<ConcreteTraits>,生成对应的HookWrapper类型。- Container通过
HookWrapper拿到成员指针的原始归属类型,在push_front中通过static_cast安全转换Derived对象到基类引用,合法访问成员指针,同时对外完全隐藏Base类的存在,保持接口简洁。
内容的提问来源于stack exchange,提问作者Fred Helmers
相关产品推荐
相关产品推荐

