Boost Spirit и абстрактный синтаксический дизайн дерева

Я использую Qi от Boost Spirit для разбора VRML 1.0. Существует групповой узел с именем Разделитель, и непосредственно под Разделителем можно хранить множество различных типов узлов. AST основан на Boost.Variant и пока выглядит длинным. Я близок к достижению лимита в 20 типов в варианте. Я знаю, что могу расширить количество типов, которые есть у варианта, но я уверен, что должен быть лучший способ спроектировать это. Идеи приветствуются.

typedef boost::variant<
Nil,
Coordinate3,
Info,
Material,
MaterialBinding,
Normal,
NormalBinding,
Texture2,
Texture2Transform,
TextureCoordinate2,
ShapeHints,
MatrixTransform,
Rotation,
Scale,
Transform,
Translation,
boost::recursive_wrapper<Separator>
> VRML1Node;

2

Решение

Вы уверены, что не оптимизируете преждевременно?? По моему опыту «когнитивные накладные расходы» варианта не увеличиваются с увеличением количества типов элементов в варианте.[1]

Вы можете захотеть

Используйте последовательность типов для указания ограниченных типов

typedef mpl::vector< Coordinate3 > types_initial;
typedef mpl::push_front< types_initial, Nil >::type types;

boost::make_variant_over< types >::type VRML1Node;

альтернативно

Вместо статического полиморфизма вы можете в этом случае пойти по пути динамического полиморфизма.

В зависимости от вашего использования, производительность не обязательно будет сильно ухудшена. Основное отличие будет

  1. чтобы получить полностью оптимизируемый код посетителя, вам нужно использовать динамическое приведение, где вариант делает тип eraruse для вас сейчас
  2. месторасположение выделения памяти может быть менее оптимальным (несмотря на то, что пользовательский распределитель может облегчить ситуацию для вас)
  3. требования к хранилищу могут быть фактически улучшены (вариант должен учитывать самый большой тип элемента; когда большинство типов элементов фактически меньше, будет эффективно выделяться меньше памяти).

    1. с практической стороны, вам, возможно, придется использовать Phoenix (семантические действия), чтобы правильно назначать атрибуты

Я не рекомендую это, но ясно, что вы могли бы даже использовать boost::any

struct poorMansVariant
{
TypeCode discriminator; // TypeCode::Nil, TypeCode::Coordinate3...
boost::any value;
};

[1] хотя ситуация может немного усложняться, когда некоторые типы элементов являются конвертируемыми / присваиваемыми, или в целом их конструкторы становятся неоднозначными. Но это другая тема

3

Другие решения

Других решений пока нет …