Boost logo

Boost Users :

Subject: Re: [Boost-users] [fusion] for_each with indices
From: Steve Lorimer (steve.lorimer_at_[hidden])
Date: 2012-07-30 19:37:47


I had a similar problem - I needed to iterate over elements of a map and
find each element's index. It works by using template recursion, iterating
from the start of the sequence, with the exit specialization being when the
type of the current element being iterated over is the same as the type of
the element in the sequence you are working with.

A natural side effect of this is that the types in the sequence need to be
unique, otherwise later duplicate types will get their index to be the
index of the first element in the sequence with the same type.

Here is my code, it may help (I posted this on stackoverflow here:
http://stackoverflow.com/questions/11698413/find-the-index-of-an-element-in-a-fusion-map
)

#include <iostream>
#include <boost/fusion/container.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/mpl.hpp>
#include <boost/fusion/include/has_key.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/fusion/include/copy.hpp>
#include <boost/fusion/include/begin.hpp>
#include <boost/fusion/include/next.hpp>
#include <boost/fusion/include/key_of.hpp>
#include <boost/fusion/iterator/key_of.hpp>

namespace fusion = boost::fusion;
namespace mpl = boost::mpl;

// given a field, returns a fusion pair of <field, field::type>
template<class field>
struct make_pair
{

    typedef typename fusion::result_of::make_pair<field, typename
field::type>::type type;
};

// given a sequence of fields, returns a fusion map which maps field
-> field::type
template<class... fields>
struct make_map
{

    typedef typename fusion::result_of::as_map<typename
mpl::transform<boost::fusion::vector<fields...>,
make_pair<mpl::_1>>::type>::type type;
};
//-------------------------------------------------------------------------------------------

// iterate through a fusion map to find the index of a given key
template<typename iter, typename key_type, typename seek_type>
struct key_index
{

    typedef typename fusion::result_of::next<iter>::type next_iter;

    typedef typename fusion::result_of::key_of<next_iter>::type next_key;

    enum { value = 1 + key_index<next_iter, next_key, seek_type>::value };
};

template<typename iter, typename seek_type>
struct key_index<iter, seek_type, seek_type>
{

    enum { value = 0 };
};
//-------------------------------------------------------------------------------------------

// copy an element from a vector to a map, if the index in the vector exists
template<typename map, typename vector, int index, bool in_vec>
struct do_copy
{

    template<typename T>

    void operator()(const vector& v, const T& dest)

    {

        const_cast<T&>(dest) = fusion::at_c<index>(v);

    }
};

template<typename map, typename vector, int index>
struct do_copy<map, vector, index, false>
{

    template<typename T>

    void operator()(const vector&, const T&)

    { }
};
//-------------------------------------------------------------------------------------------

// initialise a map with the corresponding elements in a vector,
vector may be smaller than the map
template<typename vector, typename map>
struct init
{

    init(const vector& v) : _v(v) {}

    template <typename pair> void operator()(const pair& data) const

    {

        typedef typename fusion::result_of::begin<map>::type
begin_iter;

        typedef typename fusion::result_of::key_of<begin_iter>::type key_type;

        enum { index = key_index<begin_iter, key_type, typename
pair::first_type>::value };

        enum { in_vec = fusion::result_of::size<vector>::type::value > index };

        do_copy<map, vector, index, in_vec>()(_v, data.second);

    }
private:

    const vector& _v;
};
//-------------------------------------------------------------------------------------------

struct field1 { typedef std::string type; };
struct field2 { typedef int type; };
struct field3 { typedef double type; };
struct field4 { typedef std::string type; };
struct field5 { typedef int type; };
struct field6 { typedef double type; };

struct my_map
{

    template<typename... args>

    my_map(args... a)

    {

        typedef typename fusion::vector<args...> vector;

        fusion::for_each(_map, init<vector, map>(vector(a...)));

    }

    typedef typename make_map<field1, field2, field3, field4, field5,
field6>::type map;

    map _map;
};

struct print
{

    template <typename pair>

    void operator()(pair const& data) const

    {

        std::cout << data.second << " ";

    }
};
//-------------------------------------------------------------------------------------------

int main()
{

    my_map m("hello world", 5, 2.4);

    fusion::for_each(m._map, print());

    std::cout << std::endl;

    return 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