[fusion] for_each with indices

I recently needed to iterate over a fusion sequence, calling a function for each element that depends not only on the element type but on its index (position within the sequence) as well. I didn't find anything readily available to use in conjunction with for_each, so I ended up using fold with the index as state. However, I would like to get the index as a compile time value. What would be the simpler/best way to do this? Creating an iterator adaptor that keeps track of advances to the base iterator (should I be using the iterator_facade extension mechanism)? Or perhaps zipping the sequence with some kind of infinite mpl::vector_c sequence? Agustín K-ballo Bergé.- http://fusionfenix.com

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

Agustín K-ballo Bergé <kaballo86@hotmail.com> writes:
However, I would like to get the index as a compile time value. What would be the simpler/best way to do this? Creating an iterator adaptor that keeps track of advances to the base iterator (should I be using the iterator_facade extension mechanism)? Or perhaps zipping the sequence with some kind of infinite mpl::vector_c sequence?
I would use fusion::fold with the index stored as state via a mpl::int_. Christopher

On 30/07/2012 10:23 p.m., Christopher Schmidt wrote:
Agustín K-ballo Bergé <kaballo86@hotmail.com> writes:
However, I would like to get the index as a compile time value. What would be the simpler/best way to do this? Creating an iterator adaptor that keeps track of advances to the base iterator (should I be using the iterator_facade extension mechanism)? Or perhaps zipping the sequence with some kind of infinite mpl::vector_c sequence?
I would use fusion::fold with the index stored as state via a mpl::int_.
Simple enough! I hadn't considered the possibility of changing the State type from invocation to invocation. Thank you. Agustín K-ballo Bergé.- http://fusionfenix.com
participants (3)
-
Agustín K-ballo Bergé
-
Christopher Schmidt
-
Steve Lorimer