使用 Variadic 模板(或类似机制)将类型列表传递给函数

Use Variadic templates (or a similar mechanism) to pass list of types to a function

我想为数据库实现一个 class 包装器。
目前,我正在研究 createTable 函数。
我试图让它工作的方式是,用户指定类型
作为模板参数,列名作为初始化列表, 这是函数的模板:

template <typename ... Ts>
bool createTable(const std::string & tableName, const std::initializer_list<std::string> & columnNames);

这是方法的主体:

template<typename ... Ts>
bool DatabaseConnection::createTable(const std::string &tableName, const std::initializer_list<std::string> & columnNames)
{
    constexpr size_t num_cols = sizeof...(Ts);

    assert(num_cols == columnNames.size());
    auto typetuple = std::tuple<Ts...>();

    std::vector<std::tuple<std::string, std::string>> columnNameAndType(num_cols);

    auto columnNameIterator = columnNames.begin();


    for(unsigned it = 0; it++ < columnNames.size(); it++){
        typedef std::tuple_element<it, typetuple>::type c; // non-type template argument is not a constant expression
        if(is_same<c, int> ...) //pseudocode
            std::string dbtype = "INTEGER"; //pseudocode

    }

}

遗憾的是,tuple_element 行不起作用,因为它不是真正的 常量表达式。 现在,有人可能会问,为什么我要这样称呼它: createTable<int, std::string>("Users", {"ID", "Name"}); 而不是只传递两个初始化列表?

好吧,我只想让用户远离界面——如果我能够确定 it-h 类型我可以只使用 decltype 或 is_same 之类的东西来确定数据库创建查询中使用的类型——用户只需说 he/she 想要什么类型和数据库 class 确定匹配用户请求的最佳数据库类型。

现在,它仍然可以用初始化列表来制作,但它不会是编译时间,并且 我只是想知道是否可以在完整的时间完成。

希望我对问题的解释足够了。
当然这多半是理论上的问题,但我想很多人 对这样的语法很感兴趣,我还没有在互联网上找到任何解决方案。

这个接口当然可以

一个for循环是做不到的,因为一个statement/variable/expression/etc。 for 子语句的不同评估不能有不同的类型。循环将需要通过包扩展来代替。

一个或多个私有助手成员函数可以帮助解决这个问题。使用通用 lambda 可以在一个函数定义中获得所有内容,但有点不愉快。

// private static
template <typename T>
std::string DatabaseConnection::dbTypeName()
{
    if constexpr (std::is_same_v<T, int>)
        return "INTEGER";
    // ...
    else
        static_assert(!std::is_same_v<T,T>, "Unsupported type argument");
}

template<typename ... Ts>
bool DatabaseConnection::createTable(
    const std::string &tableName,
    std::initializer_list<std::string> columnNames)
{
    constexpr size_t num_cols = sizeof...(Ts);

    assert(num_cols == columnNames.size());

    std::vector<std::tuple<std::string, std::string>> columnNameAndType;

    auto columnNameIterator = columnNames.begin();

    (columnNameAndType.emplace_back(*columnNameIterator++, dbTypeName<Ts>()), ...);

    // ...    
}