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

如何简化含基类成员指针的模板,适配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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 02:36:19