Use variadic template to convert nested typelist to flat typelist

244 Views Asked by At

The following code could be the start of an ORM implementation but I'm getting stuck (no surprises there) some of the metaprogramming aspects. The below code would be the start of developing classes that can create their tables (and later read and write their rows). But I'm already getting evil "hangman indentation" on that nested table declaration in main (anyone want to link that xkcd comic about this???). So what I'd like is to change that nested format to a flat list using a variadic template argument pack.

How can I change the nested typelist in main to a flat list using variadic templates?

#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;
}

Instead of:

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

I'd like to be able to use:

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

There are 1 best solutions below

7
On BEST ANSWER
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;
    }
};

Input:

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

Output:

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

DEMO