【问题标题】:Use variadic template to convert nested typelist to flat typelist使用可变参数模板将嵌套类型列表转换为平面类型列表
【发布时间】:2014-12-10 13:33:37
【问题描述】:

以下代码可能是 ORM 实现的开始,但我遇到了一些元编程方面的问题(这并不奇怪)。下面的代码将是开发类的开始,这些类可以创建它们的表(然后读取和写入它们的行)。但是我已经在 main 中的那个嵌套表声明上得到了邪恶的“刽子手缩进”(有人想链接那个 xkcd 漫画吗???)。所以我想要的是使用可变参数模板参数包将嵌套格式更改为平面列表。

如何使用可变参数模板将 main 中的嵌套类型列表更改为平面列表?

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

struct nil {
    static const string create() {return string("");}
};

struct required {};
struct optional {};

template <const char* nm,typename req=required>
struct serial {
    static const string create() {return string(nm)+" INTEGER PRIMARY KEY NOT NULL";}
};

template <const char* nm,typename req=required>
struct integer {
    static const string create() {return string(nm)+" INTEGER NOT NULL";}
};
template <const char* nm>
struct integer<nm,optional> {
    static const string create() {return string(nm)+" INTEGER";}
};

template<typename car,typename cdr>
struct cons {
    static const string create() {
        return
            string("\t")
            +car::create()
            +",\n"
            +cdr::create();
    }
};

template<typename car>
struct cons<car,nil> {
    static const string create() {
        return
            string("\t")+car::create();
    }
};

template<typename DDL>
struct table {
    static const string create() {
        return
            string("CREATE TABLE (\n")
            +DDL::create()
            +"\n);";
    }
};

namespace fields {
    const char id[]="id";
    const char someint[]="someint";
    const char someint2[]="someint2";
};

int main(int argc,char* argv[]) {

    typedef table<
        cons<serial<(const char*)fields::id>,
            cons<integer<(const char*)fields::someint>,
                cons<integer<
                    (const char*)fields::someint2,optional>,nil
                >
            >
        >
    > test;

    cout << test::create() << endl;

    return 0;
}

代替:

    typedef table<
        cons<serial<(const char*)fields::id>,
            cons<integer<(const char*)fields::someint>,
                cons<integer<
                    (const char*)fields::someint2,optional>,nil
                >
            >
        >
    > test;

我希望能够使用:

    typedef table<
        list<
            serial<(const char*)fields::id>,
            integer<(const char*)fields::someint>,
            integer<(const char*)fields::someint2,optional>
        >
    > test;

【问题讨论】:

    标签: c++ metaprogramming variadic-templates typelist


    【解决方案1】:
    template <typename... DDL>
    struct table {
        static const string create() {
            std::string s = "CREATE TABLE (";
            using expander = int[];
            (void)expander{0,(void(s += "\n\t" + DDL::create() + ","),0)...};
            if (sizeof...(DDL)) s.pop_back();
            s += "\n);";
            return s;
        }
    };
    

    输入:

    typedef table<
                serial<(const char*)fields::id>,
                integer<(const char*)fields::someint>,
                integer<(const char*)fields::someint2,optional>
           > test;
    

    输出:

    CREATE TABLE (
        id INTEGER PRIMARY KEY NOT NULL,
        someint INTEGER NOT NULL,
        someint2 INTEGER
    );
    

    DEMO

    【讨论】:

    • 有没有办法让扩展器知道它的列表索引?
    • @BrianJack 是的,使用index_sequence
    • @BrianJack 您需要将这些索引放在哪里?
    • 我使用了一个计数器和与在表中创建相同的模式: static int index(const char *nm) { int slot=0; int 找到=-1;使用扩展器 = int[]; (void)expander{0,(if_str_eq_assign(nm,DDL::name(),found,slot++),0)...};发现退货; } 基本上这将生成表格行的列偏移量。
    • 我发现 TMP 对于一个“标准功能”来说是相当邪恶的——我对预处理器的问题真的很少,而且它应该是邪恶的化身。 :P 我什至还没到让这个东西生成类来表示这些表的地步。我看不到任何实现类型函数的好方法(因此这些列将表明它们对于 SQL_INTEGER 是 s64,对于 SQL_FLOAT 是 double,对于 SQL_TEXT 和 SQL_BLOB 是 std::string)...列类型结构中的 value_type typedef 是简单的部分...给定列的 const char* 名称来产生这种类型的 TMP 函数,不是那么容易
    猜你喜欢
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-11
    • 2021-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多