The template next_iterator
is a type used as an attribute customization point. It is invoked by
the Karma repetitive generators (such as List
(%), Kleene
(unary *), Plus (unary +), and Repeat)
in order to get an iterator pointing to the next element of a container
holding the attributes to generate output from.

The customization point next_iterator
needs to be implemented for a specific iterator type whenever the container
this iterator belongs to is to be used as an attribute in place of a
STL container. It is applicable for generators (Spirit.Karma)
only. As a rule of thumb: it has to be implemented whenever a certain
iterator type belongs to a container which is to be passed as an attribute
to a generator normally exposing a STL container, C
and if the container type does not expose the interface of a STL container
(i.e. is_container<C>::type would normally return mpl::false_).

namespaceclient{structuse_as_container{// Expose a pair holding a pointer to the use_as_container and to the
// current element as our iterator.
// We intentionally leave out having it a 'operator==()' to demonstrate
// the use of the 'compare_iterators' customization point.
structiterator{iterator(use_as_containerconst*container,intconst*current):container_(container),current_(current){}use_as_containerconst*container_;intconst*current_;};// expose 'int' as the type of each generated element
typedefinttype;use_as_container(intvalue1,intvalue2,intvalue3):value1_(value1),value2_(value2),value3_(value3){}intvalue1_;std::stringdummy1_;// insert some unrelated data
intvalue2_;std::stringdummy2_;// insert some more unrelated data
intvalue3_;};}

as a direct attribute to the List
(%) generator. This
type does not expose any of the interfaces of an STL container. It does
not even expose the usual semantics of a container. The purpose of this
artificial example is to demonstrate how the customization points can
be used to expose independent data elements as a single container. The
example shows how to enable its use as an attribute to Karma's
repetitive generators.

// All specializations of attribute customization points have to be placed into
// the namespace boost::spirit::traits.
//
// Note that all templates below are specialized using the 'const' type.
// This is necessary as all attributes in Karma are 'const'.
namespaceboost{namespacespirit{namespacetraits{// The specialization of the template 'is_container<>' will tell the
// library to treat the type 'client::use_as_container' as a
// container holding the items to generate output from.
template<>structis_container<client::use_as_containerconst>:mpl::true_{};// The specialization of the template 'container_iterator<>' will be
// invoked by the library to evaluate the iterator type to be used
// for iterating the data elements in the container. We simply return
// the type of the iterator exposed by the embedded 'std::vector<int>'.
template<>structcontainer_iterator<client::use_as_containerconst>{typedefclient::use_as_container::iteratortype;};// The specialization of the templates 'begin_container<>' and
// 'end_container<>' below will be used by the library to get the iterators
// pointing to the begin and the end of the data to generate output from.
//
// The passed argument refers to the attribute instance passed to the list
// generator.
template<>structbegin_container<client::use_as_containerconst>{staticclient::use_as_container::iteratorcall(client::use_as_containerconst&c){returnclient::use_as_container::iterator(&c,&c.value1_);}};template<>structend_container<client::use_as_containerconst>{staticclient::use_as_container::iteratorcall(client::use_as_containerconst&c){returnclient::use_as_container::iterator(&c,(intconst*)0);}};}}}

// All specializations of attribute customization points have to be placed into
// the namespace boost::spirit::traits.
namespaceboost{namespacespirit{namespacetraits{// The specialization of the template 'deref_iterator<>' will be used to
// dereference the iterator associated with our counter data structure.
template<>structderef_iterator<client::use_as_container::iterator>{typedefclient::use_as_container::typetype;statictypecall(client::use_as_container::iteratorconst&it){return*it.current_;}};template<>structnext_iterator<client::use_as_container::iterator>{staticvoidcall(client::use_as_container::iterator&it){if(it.current_==&it.container_->value1_)it.current_=&it.container_->value2_;elseif(it.current_==&it.container_->value2_)it.current_=&it.container_->value3_;elseit.current_=0;}};template<>structcompare_iterators<client::use_as_container::iterator>{staticboolcall(client::use_as_container::iteratorconst&it1,client::use_as_container::iteratorconst&it2){returnit1.current_==it2.current_&&it1.container_==it2.container_;}};}}}

The last code snippet shows an example using an instance of the data
structure client::use_as_container to generate output
from a List (%) generator:

client::use_as_containerd2(1,2,3);// use the instance of a 'client::use_as_container' instead of a STL vector
std::cout<<karma::format(karma::int_%", ",d2)<<std::endl;// prints: '1, 2, 3'

As you can see, the specializations for the customization points as defined
above enable the seamless integration of the custom data structure without
having to modify the output format or the generator itself.