February 21, 2019
Hot Topics:

The Story of a WML Generator

  • September 19, 2005
  • By Radu Braniste
  • Send Email »
  • More Articles »

Filtering was moved outside elements and is attached as a policy to GenericElement. Additional run-time safety was added via LateInsertCheck—more details when discussing the run-time features. Elements are tag typed to avoid circular dependencies and extra complexity (TagTypes.h):

struct IBreakImpl{};
struct IHeadImpl{};
struct IAnchorImpl{};
struct IParagraphImpl{};
struct ICardImpl{};

The IxxxImpl structures are not intended to be manipulated polymorphically and one might take the same precautions as with GenericElement, which has a non-virtual protected destructor.

Please note in the code above constructs of type:


This C++ lookup requirement is described in detail in [8].

Elements take as a template parameter the class they inherit from, thus allowing for different filters. Filters are defined separately (filters.h) and of course different implementations can coexist, the one to be used being selected at compile time. A filter acts mostly like an enabler—allowing or disallowing the compilation based on the filter parameter type.

struct BaseFilter
struct ParagraphFilter
   static void filter(const IAnchorImpl&){}
struct HeadFilter
   static void filter(const IBreakImpl&){}
struct CardFilter
   static void filter(const IParagraphImpl&){}
template < class P>
struct DeckFilter
   static void filter(const IHeadImpl& e)
      static void filter(const ICardImpl& e)
struct HeadBeforeBodyCheck
   static bool headIsFirstInADeck ;
   static void check(const IHeadImpl& e)
      assert (!headIsFirstInADeck && "head was used already");
      headIsFirstInADeck = true;
      static void check(const ICardImpl& e)
      assert (headIsFirstInADeck && "attempt to insert before head" );
bool HeadBeforeBodyCheck::headIsFirstInADeck = false;

DeckFilter offers a naïve example of a composite filter—checking at run-time whether a Header was inserted before the Cards in a Deck.

Here is an usage example (wmlExecution1.h):

   typedef CardImpl< GenericElement<CardFilter>, ICardImpl> Card;
   typedef HeadImpl<GenericElement<HeadFilter>, IHeadImpl> Head;
   typedef BreakImpl< GenericElement<BaseFilter>, IBreakImpl> Break;
   typedef DeckImpl< GenericElement<DeckFilter<HeadBeforeBodyCheck> >,
      IDeckImpl> Deck;
   typedef ParagraphImpl< GenericElement<ParagraphFilter>,
      IParagraphImpl> Paragraph;
   typedef AnchorImpl< GenericElement<BaseFilter>,
      IAnchorImpl> Anchor;
void doReadWML()
      typedef WML_TYPEDEF_HELPER::Card Card;
      typedef WML_TYPEDEF_HELPER::Head Head;
      typedef WML_TYPEDEF_HELPER::Break Break;
      typedef WML_TYPEDEF_HELPER::Deck Deck;
      typedef WML_TYPEDEF_HELPER::Paragraph Paragraph;
      typedef WML_TYPEDEF_HELPER::Anchor Anchor;
   Paragraph p;
   Break br;
   Head hd;
   Deck dk;
   Anchor a("href", "html");
   Card c;
   std::cout << static_cast<const std::string&>(dk) << std::endl;

WML_TYPEDEF_HELPER isolates the typedef declarations from the rest of the code, as an additional reusability unit.

Attempts like




are rejected by the compiler.

On the other hand,