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

如何实现可同时接收值与类型作为载荷的C++模板栈

实现方案

首先明确C模板的基础语法限制:类模板的同一个形参位置无法原生同时接收类型实参和非类型实参,两类参数分属完全独立的语法范畴,编译器在模板解析阶段会做严格校验,没有标准C语法可以直接绕开这个限制。
不过我们可以通过轻量标签类+模板偏特化的方案,用同一套StackNode实现同时支持值、类型两种载荷,仅需要对其中一类载荷做极薄的无开销包装,核心逻辑完全复用。
以下是C++17及以上标准可用的实现,默认让值载荷的写法和预期完全一致,类型载荷仅需加单字符级别的包装:

#include <string>
#include <type_traits>

// 栈结束标记
struct StackEmptyNode {};

// 类型载荷标签,空类无任何运行时开销
template<typename T>
struct TypeTag { using type = T; };
// 全局constexpr模板,简化类型包装的书写
template<typename T>
inline constexpr TypeTag<T> t{};

// StackNode主模板:第一个参数为auto非类型形参,直接接收值载荷
template<auto Payload, typename Next = StackEmptyNode>
struct StackNode {
    // 值载荷统一接口
    static constexpr auto value = Payload;
    using next = Next;
    static constexpr bool is_value_node = true;
};

// 偏特化:匹配传入TypeTag实例的场景,对应类型载荷
template<typename T, typename Next>
struct StackNode<t<T>, Next> {
    // 类型载荷统一接口
    using type = T;
    using next = Next;
    static constexpr bool is_value_node = false;
};

// C++20及以上可加概念约束,优化编译报错信息
#if __cplusplus >= 202002L
#include <concepts>
template<typename N>
concept ValidStackNode = std::is_same_v<N, StackEmptyNode> || requires { typename N::next; };

template<auto Payload, ValidStackNode Next = StackEmptyNode>
struct StackNode {
    static constexpr auto value = Payload;
    using next = Next;
    static constexpr bool is_value_node = true;
};

template<typename T, ValidStackNode Next>
struct StackNode<t<T>, Next> {
    using type = T;
    using next = Next;
    static constexpr bool is_value_node = false;
};
#endif

// ------------------------------
// 使用示例
// ------------------------------
// 值栈:写法和预期完全一致,不需要额外包装
using ValueStack = StackNode<3, StackNode<4, StackNode<9>>>;
// 类型栈:仅需要给类型套t<>包装,书写成本极低
using TypeStack = StackNode<t<int>, StackNode<t<float>, StackNode<t<std::string>>>>;

// 接口校验
static_assert(ValueStack::value == 3);
static_assert(ValueStack::next::value == 4);
static_assert(std::is_same_v<TypeStack::type, int>);
static_assert(std::is_same_v<TypeStack::next::type, float>);

如果你日常使用类型载荷更多,只需要把逻辑反转:主模板第一个参数用类型形参接收类型,值载荷通过ValueHolder包装即可,写法和上述实现完全对称。
这套实现下两类节点的访问逻辑高度统一,后续实现push、pop、遍历等元函数时,可以通过is_value_node标记做统一分发,不需要为两类载荷写冗余逻辑。

非标准扩展方案:GCC/Clang提供了__builtin_pack_type等内置编译期函数,可以实现完全无包装的两类传参,但这类写法不属于标准C++,跨编译器兼容性差,不建议在生产环境使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 05:21:40