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

带枚举模板参数的模板类如何实现免修改的工厂函数?

实现方案

核心思路利用编译期生成所有枚举值对应的构造函数映射,后续新增枚举仅需修改枚举定义本身,无需调整工厂相关代码。

最优方案(枚举连续场景)

该方案要求枚举默认从0开始连续赋值(C++枚举默认行为),仅需在枚举末尾新增一个count标记项即可,运行时效率最高。

步骤1:修改Colour枚举定义

enum class Colour
{
  red,
  blue,
  orange,
  count // 所有新增枚举值必须放在该行之前
};

原有PencilBase和Pencil模板类无需任何修改。

步骤2:实现工厂逻辑

#include <utility>
#include <array>
#include <stdexcept>
#include <memory>

// 编译期生成所有颜色对应的铅笔构造函数数组
template <std::size_t... Is>
constexpr auto build_factory_array(std::index_sequence<Is...>)
{
    return std::array{
        []() -> std::unique_ptr<PencilBase> {
            return std::make_unique<Pencil<static_cast<Colour>(Is)>>();
        }...
    };
}

// 全局工厂数组,编译期完成初始化
constexpr auto g_pencil_factory = build_factory_array(
    std::make_index_sequence<static_cast<std::size_t>(Colour::count)>{}
);

// 对外暴露的工厂函数
std::unique_ptr<PencilBase> createColourPencil(Colour c)
{
    const auto idx = static_cast<std::size_t>(c);
    if (idx >= g_pencil_factory.size()) {
        throw std::invalid_argument("无效的颜色枚举值");
    }
    return g_pencil_factory[idx]();
}

这里用std::unique_ptr替代裸指针避免内存泄漏,如需返回裸指针直接调整返回类型和构造逻辑即可。

方案优势

  • 运行时效率极高,直接数组索引调用,无任何查找开销
  • 新增枚举仅需在Colour::count前添加枚举项,完全无需修改工厂代码
  • 编译期完成所有逻辑生成,无额外运行时初始化开销

注意事项

  • 不要手动为枚举成员赋值,保持默认从0连续递增的规则
  • 兼容C++14及以上标准

可选方案(枚举不连续场景)

如果枚举值不连续,或不想添加count标记,可以用自动注册机制,缺点是需要确保所有用到的Pencil<Colour>模板特化都被显式实例化,否则运行时会找不到对应构造函数。

实现代码

#include <map>
#include <functional>
#include <stdexcept>
#include <memory>

// 全局注册表
struct PencilRegistry {
    using Creator = std::function<std::unique_ptr<PencilBase>()>;
    static std::map<Colour, Creator>& get() {
        static std::map<Colour, Creator> instance;
        return instance;
    }

    template <Colour c>
    struct RegisterHelper {
        RegisterHelper() {
            get()[c] = []() {
                return std::make_unique<Pencil<c>>();
            };
        }
    };
};

// 在Pencil模板类中添加静态注册成员
template <Colour c>
class Pencil : public PencilBase
{
    void paint() override
    {
        // use c
    }
    inline static PencilRegistry::RegisterHelper<c> _register{};
};

// 工厂函数实现
std::unique_ptr<PencilBase> createColourPencil(Colour c)
{
    auto& registry = PencilRegistry::get();
    auto it = registry.find(c);
    if (it == registry.end()) {
        throw std::invalid_argument("无效的颜色枚举值");
    }
    return it->second();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 06:54:02