Determine the Type of the Iterator of a Container (Karma)

| Home | Libraries | People | FAQ | More

##### Determine the Type of the Iterator of a Container (Karma)

###### container_iterator

The template `container_iterator` is a template meta-function 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 determine the type of the iterator to use to iterate over the items to be exposed as the elements of a container.

###### Module Headers

    #include <boost/spirit/home/support/container.hpp>

Also, see Include Structure.

| Note
This header file does not need to be included directly by any user program as it is normally included by other Spirit header files relying on its content.

###### Namespace

Name
`boost::spirit::traits`

###### Synopsis

    template <typename Container, typename Enable>
    struct container_iterator
    {
        typedef <unspecified> type;
    };

###### Template parameters

Parameter | Description | Default
--- | --- | ---
`Container` | The type, `Container` for which the iterator type has to be returned | none
`Enable` | Helper template parameter usable to selectively enable or disable certain specializations of `container_iterator` utilizing SFINAE (i.e. `boost::enable_if` or `boost::disable_if`). | `void`

###### Notation

`C`

  A container type the iterator type needs to be evaluated for.

###### Expression Semantics

Expression | Semantics
--- | ---
`container_iterator<C>::type` | Result of the metafunction that evaluates the type to be used as the iterator for accessing all elements of a container, `C`.

The returned type conceptually needs to be equivalent to a standard forward iterator. But it does not have to expose the standardized interface. If this customization point is implemented for a certain container type, all related customization points need to be implemented as well (see Related Attribute Customization Points below). This encapsulates the specific iterator interface required for a given type. The minimal requirements for a type to be exposed as an iterator in this context are:

- it needs to be comparable for equality (see `compare_iterators`),
- it needs to be incrementable (see `next_iterator`),
- it needs to be dereferencible (see `deref_iterator`).

###### Predefined Specializations

Spirit predefines specializations of this customization point for several types. The following table lists those types together with the types returned by the embedded typedef `type`:

Template Parameters | Value
--- | ---
`C` | Returns `C::iterator`.
`C const` | Returns `C::const_iterator`.
`unused_type` | Returns `unused_type` `const*`.

###### When to implement

The customization point `container_iterator` needs to be implemented for a specific type whenever this type 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 type is to be passed as an attribute to a generator normally exposing a STL container, `C` and if the type does not expose the interface of a STL container (i.e. `is_container<C>::type` would normally return `mpl::false_`).

###### Related Attribute Customization Points

If this customization point is implemented, the following other customization points might need to be implemented as well.

Name | When to implement
--- | ---
`is_container` | Needs to be implemented whenever a type is to be used as a container attribute in Karma.
`container_iterator` | Karma: List (`%`), Kleene (unary `*`), Plus (unary `+`), Repeat.
`begin_container` | Karma: List (`%`), Kleene (unary `*`), Plus (unary `+`), Repeat.
`end_container` | Karma: List (`%`), Kleene (unary `*`), Plus (unary `+`), Repeat.
`deref_iterator` | Karma: List (`%`), Kleene (unary `*`), Plus (unary `+`), Repeat.
`next_iterator` | Karma: List (`%`), Kleene (unary `*`), Plus (unary `+`), Repeat.
`compare_iterators` | Karma: List (`%`), Kleene (unary `*`), Plus (unary `+`), Repeat.

###### Example

Here are the header files needed to make the example code below compile:

    #include <boost/spirit/include/karma.hpp>
    #include <iostream>
    #include <vector>

The example (for the full source code please see here: customize_embedded_container.cpp) uses the data structure

    namespace client
    {
        struct embedded_container
        {
            // expose the iterator of the embedded vector as our iterator
            typedef std::vector<int>::const_iterator iterator;

            // expose the type of the held data elements as our type
            typedef std::vector<int>::value_type type;

            // this is the vector holding the actual elements we need to generate
            // output from
            std::vector<int> data;
        };
    }

as a direct container attribute to the List (`%`) generator. In order to make this data structure compatible we need to specialize a couple of attribute customization points: `is_container`, `container_iterator`, `begin_container`, and `end_container`. As you can see the specializations simply expose the embedded `std::vector<int>` as the container to use. We don't need to specialize the customization points related to iterators (`deref_iterator`, `next_iterator`, and `compare_iterators`) as we expose a standard iterator and the default implementation of these customizations handles standard iterators out of the box.

    // 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'.
    namespace boost { namespace spirit { namespace traits
    {
        // The specialization of the template 'is_container<>' will tell the
        // library to treat the type 'client::embedded_container' as a
        // container holding the items to generate output from.
        template <>
        struct is_container<client::embedded_container const>
          : 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 <>
        struct container_iterator<client::embedded_container const>
        {
            typedef client::embedded_container::iterator type;
        };

        // 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.
        // These specializations simply return the 'begin' and 'end' iterators as
        // exposed by the embedded 'std::vector<int>'.
        //
        // The passed argument refers to the attribute instance passed to the list
        // generator.
        template <>
        struct begin_container<client::embedded_container const>
        {
            static client::embedded_container::iterator
            call(client::embedded_container const& d)
            {
                return d.data.begin();
            }
        };

        template <>
        struct end_container<client::embedded_container const>
        {
            static client::embedded_container::iterator
            call(client::embedded_container const& d)
            {
                return d.data.end();
            }
        };
    }}}

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

    client::embedded_container d1;    // create some test data
    d1.data.push_back(1);
    d1.data.push_back(2);
    d1.data.push_back(3);

    // use the instance of an 'client::embedded_container' instead of a
    // STL vector
    std::cout << karma::format(karma::int_ % ", ", d1) << 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.

For other examples of how to use the customization point `container_iterator` please see here: use_as_container and counter_example.