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

Customization of Spirit's Attribute Handling

Determine if a Type Should be Treated as a Container (Qi and Karma)
Transform an Attribute to a Different Type (Qi and Karma)
Store a Parsed Attribute Value (Qi)
Store Parsed Attribute Values into a Container (Qi)
Re-Initialize an Attribute Value before Parsing (Qi)
Extract an Attribute Value to Generate Output (Karma)
Extract Attribute Values to Generate Output from a Container (Karma)
Create Components from Attributes
Why do we need Attribute Customization Points
[Important] Important

Before you read on please be aware that the interfaces described in this section are not finalized and may change in the future without attempting to be backwards compatible. We document the customization point interfaces anyways as we think they are important. Understanding customization points helps understanding Spirit. Additionally they prove to be powerful tools enabling full integration of the user's data structures with Qi's parsers and Karma's generators.

Spirit has been written with extensibility in mind. It provides many different attribute customization points allowing to integrate custom data types with the process of parsing in Spirit.Qi or output generation with Spirit.Karma. All attribute customization points are exposed using a similar technique: full or partial template specialization. Spirit generally implements the main template, providing a default implementation. You as the user have to provide a partial or full specialization of this template for the data types you want to integrate with the library. In fact, the library uses these customization points itself for instance to handle the magic of the unused_type attribute type.

Here is an example showing the container_value customization point used by different parsers (such as Kleene, Plus, etc.) to find the attribute type to be stored in a supplied STL container:

template <typename Container, typename Enable/* = void*/>
struct container_value
  : detail::remove_value_const<typename Container::value_type>
{};

This template is instantiated by the library at the appropriate places while using the supplied container type as the template argument. The embedded type is used as the attribute type while parsing the elements to be store in that container.

The following example shows the predefined specialization for unused_type:

template <>
struct container_value<unused_type>
{
    typedef unused_type type;
};

which defines its embedded type to be unused_type as well, this way propagating the 'don't care' attribute status to the embedded parser.

All attribute customization points follow the same scheme. The last template parameter is always typename Enable = void allowing to apply SFINAE for fine grained control over the template specialization process. But most of the time you can safely forget about its existence.

The following sections will describe all customization points, together with a description which needs to be specialized for what purpose.

The Usage of Customization Points

The different customizations points are used by different parts of the library. Part of the customizations points are used by both, Spirit.Qi and Spirit.Karma, whereas others are specialized to be applied for one of the sub-libraries only. We will explain when a specific customization point needs to be implemented and, equally important, which customization points need to be implemented at the same time. Often it is not sufficient to provide a specialization for one single customization point only, in this case you as the user have to provide all necessary customizations for your data type you want to integrate with the library.


PrevUpHomeNext