Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Click here to view the latest version of this page.
PrevUpHomeNext
Determine the Type of the Iterator of a Container
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] 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:

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

Semantics

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

traits::is_container

Needs to be implemented whenever a type is to be used as a container attribute in Karma.

traits::container_iterator

Karma: List (%), Kleene (unary *), Plus (unary +), Repeat.

traits::begin_container

Karma: List (%), Kleene (unary *), Plus (unary +), Repeat.

traits::end_container

Karma: List (%), Kleene (unary *), Plus (unary +), Repeat.

traits::deref_iterator

Karma: List (%), Kleene (unary *), Plus (unary +), Repeat.

traits::next_iterator

Karma: List (%), Kleene (unary *), Plus (unary +), Repeat.

traits::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: traits::is_container, traits::container_iterator, traits::begin_container, and traits::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 (traits::deref_iterator, traits::next_iterator, and traits::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.


PrevUpHomeNext