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

如何为模板化Queue类实现适配Vec的可选构造函数

前置信息

我正在实现一个队列,现有如下Vec类:

#include <cstddef>
#include <span>

template<typename T, size_t Extent, bool Dynamic = (Extent == std::dynamic_extent)>
class Vec {
public:
    constexpr size_t capacity(void) const;
    ~Vec();
};

template<typename T, size_t Extent>
class Vec<T, Extent, true> {
    // 动态版本
public:
    Vec(size_t capacity);
};

template<typename T, size_t Extent>
class Vec<T, Extent, false> {
    // 静态大小版本
public:
    constexpr Vec() = default;
};

换句话说,当Extent不等于std::dynamic_extent时,Vec可通过constexpr Vec()构造;否则必须传入大小,使用Vec(size_t capacity)构造,该设计模仿std::span的API。

问题

如何在新类Queue中集成该设计,使两类共享大部分功能同时拥有特化构造函数?例如我希望写出如下代码:

template<typename T, size_t Extent = std::dynamic_extent>
class Queue {
public:
    template</* 仅当Extent != std::dynamic_extent时启用 */>
    constexpr Queue() {}

    template</* 仅当Extent == std::dynamic_extent时启用 */>
    Queue(size_t size) : m_slots(size) {}

    // 其他方法...
private:
    Vec<T, Extent> m_slots;
    // 其他成员变量...
};

我知道可以添加与Vec<T>匹配的bool Dynamic参数,但这样需要重复所有字段和函数定义。

我尝试了多种模板表达式(仅展示constexpr Queue()的模板,Queue(size_t size)的表达式为其逆):

尝试1:带默认参数的匿名模板(可能无效)

template<typename = typename std::enable_if_t<Extent != std::dynamic_extent>>
constexpr Queue() {}

尝试2:模仿C++文档中std::enable_if的用法

template<std::enable_if_t<Extent != std::dynamic_extent, bool> = true>

两种尝试均编译失败,错误信息如下:

/usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/type_traits:2608:44: error: no type named 'type' in 'std::enable_if<false, bool>'; 'enable_if' cannot be used to disable this declaration
 2608 |     using enable_if_t = typename enable_if<_Cond, _Tp>::type;
      |                                            ^~~~~
../src/queues/spsc.hh:34:16: note: in instantiation of template type alias 'enable_if_t' requested here
   34 |         template<std::enable_if_t<Extent == std::dynamic_extent, bool> = true>
      |

如何实现该行为?是否有我未考虑到的更优模式?

解决方案

你的问题核心在于:类模板的成员模板直接使用类模板参数作为enable_if条件时,编译器会在实例化类模板时尝试解析所有成员模板的enable_if表达式,条件不满足时就会触发错误。以下是几种可行的解决方式:

方法1:C++20 requires 约束(最简洁)

直接用requires表达式约束构造函数,编译器会在重载决议阶段自动过滤不符合条件的构造函数,不会触发enable_if的实例化错误:

#include <cstddef>
#include <span>

// 保留原有Vec定义
template<typename T, size_t Extent, bool Dynamic = (Extent == std::dynamic_extent)>
class Vec {
public:
    constexpr size_t capacity(void) const;
    ~Vec();
};

template<typename T, size_t Extent>
class Vec<T, Extent, true> {
public:
    Vec(size_t capacity);
};

template<typename T, size_t Extent>
class Vec<T, Extent, false> {
public:
    constexpr Vec() = default;
};

template<typename T, size_t Extent = std::dynamic_extent>
class Queue {
public:
    constexpr Queue() requires (Extent != std::dynamic_extent) 
        : m_slots() {}

    Queue(size_t size) requires (Extent == std::dynamic_extent)
        : m_slots(size) {}

    // 其他共享方法
private:
    Vec<T, Extent> m_slots;
};

方法2:兼容C++17的enable_if写法

如果需要兼容C++17,可引入一个依赖于成员模板的参数,让enable_if的条件变为成员模板的依赖项,避免类模板实例化时直接解析条件:

template<typename T, size_t Extent = std::dynamic_extent>
class Queue {
public:
    template<size_t E = Extent, std::enable_if_t<E != std::dynamic_extent, int> = 0>
    constexpr Queue() : m_slots() {}

    template<size_t E = Extent, std::enable_if_t<E == std::dynamic_extent, int> = 0>
    Queue(size_t size) : m_slots(size) {}

    // 其他共享方法
private:
    Vec<T, Extent> m_slots;
};

方法3:拆分公共逻辑+部分特化(更易维护)

如果Queue的大部分功能在动态/静态版本中一致,可把公共逻辑提取到基类,再对Queue做部分特化,避免成员模板的复杂约束:

// 公共基类,存放所有共享功能
template<typename T, size_t Extent>
class QueueBase {
protected:
    Vec<T, Extent> m_slots;
public:
    // 共享方法示例
    size_t capacity() const { return m_slots.capacity(); }
};

// 动态版本特化
template<typename T>
class Queue<T, std::dynamic_extent> : public QueueBase<T, std::dynamic_extent> {
public:
    Queue(size_t size) : QueueBase<T, std::dynamic_extent>{size} {}
};

// 静态版本特化
template<typename T, size_t Extent>
class Queue<T, Extent> : public QueueBase<T, Extent> {
public:
    constexpr Queue() = default;
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 06:47:21