Boost logo

Boost Users :

Subject: Re: [Boost-users] [Tuple] Help getting started with Tuple-based meta-programming
From: Dominique Devienne (ddevienne_at_[hidden])
Date: 2009-03-20 16:59:54


On Fri, Mar 20, 2009 at 3:01 PM, Steven Watanabe <watanabesj_at_[hidden]> wrote:
> In this case, I think Boost.Fusion can help (warning untested).
>
> #include <boost/fusion/include/for_each.hpp>
> #include <boost/fusion/include/boost_tuple.hpp>
>
> struct get_t {
>   ResultSet& r;
>   int& n;
>   template<class T>
>   void operator()(T& t) const {
>       t = r.get<T>(n++);
>   }
> };
>
> template<Row>
> void get_rows(const char* query, std::vector<Row>& out) {
>   ResultSet rset = sql_exec(query);
>   while(rset.hasMoreRows()) {
>       Row row;
>       int n = 0;
>       get_t getter = { rset, n };
>       boost::fusion::for_each(row, getter);
>       out.push_back(row);
>   }
> }

Simply amazing Steven :) Thanks a lot!

Here's the code I ended up with, which reveals more context.

Many thanks. I can't believe the quality and speed of your answer frankly.

You made me day. Sincerely, --DD

#include <sqlite3pp.h>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
...

// Courtesy Steven Watanabe, Mar 20, 2009, boost-users mailing list.
struct get_rows_binder {
    sqlite3pp::query& qry;
    int& bind_idx;
    template <class T> void operator()(const T& t) const {
        qry.bind(bind_idx++, t);
    }
};

struct get_rows_getter {
    sqlite3pp::query::iterator& i;
    int& col_idx;
    template <class T> void operator()(T& t) const {
        t = i->get<T>(col_idx++);
    }
};

template <class ROW, class BIND> void get_rows(
    const char* query, const BIND& binds, std::vector<ROW>& out
) {
    sqlite3pp::database& conn = DBConnection::instance()->db();
    sqlite3pp::query qry(conn);

    checkerr(conn, qry.prepare(query));
    if (boost::tuples::length<BIND>::value > 0) {
        int bind_idx = 1; // 1-based for binds
        get_rows_binder binder = { qry, bind_idx };
        boost::fusion::for_each(binds, binder);
    }

    for (sqlite3pp::query::iterator i = qry.begin(); i != qry.end(); ++i) {
        ROW row;
        int col_idx = 0; // 0-based for result-set columns
        get_rows_getter getter = { i, col_idx };
        boost::fusion::for_each(row, getter);
        out.push_back(row);
    }
}

template <class ROW> void get_rows(const char* query, std::vector<ROW>& out) {
    get_rows(query, boost::make_tuple(), out);
}

void TypeIdTests::test_rtti_vtable() {
...
    {
        typedef boost::tuple<sqlite_int64> Row;
        std::vector<Row> rset;
        get_rows("select count(*) from rtti", rset);
        CPPUNIT_ASSERT_EQUAL(1, (int)rset.size());
        CPPUNIT_ASSERT_EQUAL(expected_count, boost::get<0>(rset[0]));
    }

    {
        typedef boost::tuple<unsigned short, unsigned short, unsigned
short> Row;
        std::vector<Row> rset;
        get_rows(
            "select type, is_a, distance from rtti where type = :1 and
is_a = :2",
            boost::make_tuple(ts.transient_id(), ag.transient_id()), rset
        );
        CPPUNIT_ASSERT_EQUAL(1, (int)rset.size());
        CPPUNIT_ASSERT_EQUAL(ts.transient_id(), boost::get<0>(rset[0]));
        CPPUNIT_ASSERT_EQUAL(ag.transient_id(), boost::get<1>(rset[0]));
        CPPUNIT_ASSERT_EQUAL(unsigned short(1), boost::get<2>(rset[0]));
    }
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net