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

编译时SQL数据库:如何创建含模板参数元素的std::array?

编译时SQL数据库的表集合存储问题

我正在开发一个纯编译时SQL数据库作为学习项目,当前遇到的问题是:需要存储若干模板参数不同但功能一致的Table元素,希望用简单数据结构替代工作量较大的“基于表生成数据库类”方案。

现有代码定义

Table类以CompileTimeString为模板参数(CompileTimeString是const char[N]的抽象,附带便捷特性,所有表及其名称均在编译时确定):

template<CompileTimeString TableName, CompileTimeString OtherData>
class Table
{
public:
    //... 表的核心功能实现
};

我期望的Database类结构(当前写法存在问题):

class Database
{
public:
    template<CompileTimeString TableName, CompileTimeString OtherData>
    void add_table()
    {
        // 需要实现:构造Table实例并添加到数组
    }

    std::array<Table, 10> tables; // 此处写法错误,Table必须指定模板参数
};

需求是通过调用add_table<CompileTimeString("TableName"), CompileTimeString("OtherData")>();在编译时完成表的添加,将实例存入tables数组。之前尝试的写法未成功:

template<CompileTimeString... TableNames, DatabaseSchemaDescriptorPair... Descriptors>
std::array<Table<TableNames, Descriptors>..., 10> tables;

我的目标是学习模板元编程,想知道是否有可行的实现方案。


解决方案思路

不同模板参数的Table是完全不同的类型,而std::array要求所有元素类型一致,因此直接存储Table实例行不通。以下两种模板元编程思路可以解决问题:

方法1:基类+编译时初始化的异构容器(类型擦除)

先定义非模板基类统一接口,让所有Table特化继承它,再用std::array存储基类指针,通过模板元编程在编译时完成初始化:

// 定义统一的表基类
class TableBase
{
public:
    virtual ~TableBase() = default;
    virtual const CompileTimeString& get_name() const = 0;
};

// 修改Table类继承基类
template<CompileTimeString TableName, CompileTimeString OtherData>
class Table : public TableBase
{
public:
    const CompileTimeString& get_name() const override { return TableName; }
    static constexpr CompileTimeString name = TableName;
    //... 原有功能
};

// 用模板类接收编译时表列表
template<class... Tables>
class Database
{
public:
    // 编译时初始化数组
    std::array<std::unique_ptr<TableBase>, sizeof...(Tables)> tables = {
        std::make_unique<Tables>()...
    };

    // 编译时按名称查找表
    template<CompileTimeString TargetName>
    TableBase* get_table()
    {
        return find_table<TargetName>(std::make_index_sequence<sizeof...(Tables)>{});
    }

private:
    template<CompileTimeString TargetName, size_t... Idx>
    TableBase* find_table(std::index_sequence<Idx...>)
    {
        // 编译时遍历匹配表名
        return ((std::get<Idx>(tables)->get_name() == TargetName) ? std::get<Idx>(tables).get() : nullptr)...;
    }
};

使用方式:

Database<
    Table<CompileTimeString("User"), CompileTimeString("id int, name varchar")>,
    Table<CompileTimeString("Order"), CompileTimeString("id int, user_id int")>
> db;

// 编译时获取指定表
auto* user_table = db.get_table<CompileTimeString("User")>();

方法2:std::tuple存储异构实例+编译时类型查找

如果不需要运行时多态,直接用std::tuple存储不同类型的Table,通过元函数在编译时定位目标表:

template<class... Tables>
class Database
{
public:
    std::tuple<Tables...> tables;

    Database() : tables(Tables{}...) {}

    // 编译时按名称获取表
    template<CompileTimeString TargetName>
    auto& get_table()
    {
        return std::get<find_table_index<TargetName, Tables...>::value>(tables);
    }

private:
    // 元函数:查找目标表在tuple中的索引
    template<CompileTimeString TargetName, class First, class... Rest>
    struct find_table_index
    {
        static constexpr size_t value = 
            (First::name == TargetName) ? 0 : 1 + find_table_index<TargetName, Rest...>::value;
    };

    template<CompileTimeString TargetName>
    struct find_table_index<TargetName>
    {
        static_assert(false, "指定名称的表不存在");
    };
};

// 给Table添加静态名称成员
template<CompileTimeString TableName, CompileTimeString OtherData>
class Table
{
public:
    static constexpr CompileTimeString name = TableName;
    //... 原有功能
};

使用方式:

Database<
    Table<CompileTimeString("User"), CompileTimeString("id int, name varchar")>,
    Table<CompileTimeString("Order"), CompileTimeString("id int, user_id int")>
> db;

// 编译时获取表(类型完全匹配)
auto& order_table = db.get_table<CompileTimeString("Order")>();

原写法失败原因

  1. std::array要求元素类型统一,而Table<Name1, Data1>与Table<Name2, Data2>是不同类型,无法直接存入同一数组;
  2. 尝试的参数包写法中,TableNames...和Descriptors...是两个独立参数包,无法一一对应绑定到Table的两个模板参数上。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 15:30:20