шаблоны — Design C ++ DSL для нотирования и передачи деревьев

Короче

Я пытаюсь разработать более приятный интерфейс C ++ для библиотеки C, которая отправляет древовидные выражения по каналу связи (а-ля iostreams vs stdio). Я не уверен, возможно ли вообще создать DSL в C ++ для обозначения этих деревьев избегая при этом времени выполнения, и если да, то как.

Упрощенное объяснение библиотеки C

Существует библиотека C, которая может отправлять «выражения» по каналу связи. «Выражение» здесь означает древовидную структуру, которую можно удобно записать способом, аналогичным вызовам функций.

Например,

f(1, 2, g(3), "foo")

обозначает это дерево:

Mathematica графика

Некоторые из вас могут узнать Mathematica на данный момент, но я решил оставить это, поскольку это не имеет отношения к вопросу.

Мы ссылаемся на f как голова а также 1, 2, g(3) как аргументы.

Чтобы отправить это выражение, мы напишем следующее:

putHead("f" /* name */, 3 /* argument count */);
putInteger(1);
putInteger(2);
putHead("g" /* name */, 1 /* argument count */);
putInteger(3);
putString("foo");

Вопрос

Можно ли разработать для этого более удобный C ++ API со следующими функциями?

  1. Более лаконично написать (подумать iostreams против stdio)
  2. Избавляет от необходимости явно указывать количество аргументов для каждой головы; вместо этого используется удобное обозначение (аналогично f(1,2,g(3)) сверху) из которого автоматически выводится число аргументов
  3. Достигает (2) без накладных расходов времени выполнения (то есть выводит количество аргументов во время компиляции)
  4. Нужно использовать вышеописанный интерфейс C за кулисами

Я могу сделать (1) с потоковым интерфейсом (то есть нет необходимости явно указывать тип Integer, String и т. Д. Каждого аргумента). Я могу сделать (2) таким образом, что требует дополнительных вычислений во время выполнения. Но я не знаю, если (2) / (3) все вместе возможны с учетом особенностей C ++. В конечном итоге я хотел бы иметь удобную запись для этих выражений в самом C ++.

Так можно ли создать DSL в C ++ для этого избегая всех накладных расходов во время выполнения? Если да, то как? Я не обязательно ищу полное решение с кодом в качестве ответа, просто несколько указателей для начала или краткое изложение подхода, который, вероятно, сработает.

4

Решение

Я могу придумать несколько способов представления дерева в C ++. Реализация некоторых из них (# 1, # 2) будет включать построение промежуточной структуры, а затем вызов функции C в конце. Другие (# 5, # 6) могут вызывать функции C по мере необходимости, потому что число дочерних элементов любого узла известно во время компиляции.

1) Использование свободного интерфейса и перегрузки:

Tree()
.head("f")
.put(1)
.put(2)
.head("g")
.put(3)
.end()
.put("foo")
.end();

2) Или, альтернативно, без вызовов end ():

head("f")
.put(1)
.put(2)
.put(head("g")
.put(3))
.put("foo");

3) Использование оператора<<:

Tree("f")
<< 1
<< 2
<< (Tree("g") << 3)
<< "foo";

4) Использование оператора ():

Tree("f")
(1)
(2)
(Tree("g")(3))
("foo")

5) Использование std :: initializer_list, где Node — это тип, который неявно конвертируется из int и std :: string:

Tree { "f", {
1,
2,
{ "g", { 3 } }
"foo",
} }

6) Использование вариадических шаблонов:

head("f").put(
1,
2,
head("g").put(3)
"foo");
0

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

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

По вопросам рекламы [email protected]