Генерация массива препроцессора

Я пытаюсь создать макрос для замены определения функции. Этот макрос должен регистрировать имя функции в некотором массиве, чтобы другой макрос мог что-то делать с элементами массива.

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

Прочитав немного, я взглянул на препроцессор boost. К сожалению, похоже, что нет способа «сохранить» новый массив.
Я хотел бы сделать что-то вроде этого:

#define SOME_ARRAY (0, ())
#define CONSOLE_COMMAND(a) \
#redefine SOME_ARRAY BOOST_PP_ARRAY_PUSH_BACK(SOME_ARRAY, #a) \
void a(some_arguments)

К сожалению, насколько мне известно, переопределения не существует, и #define нельзя использовать в макросе (пожалуйста, исправьте меня, если я ошибаюсь).

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

Есть ли способ сделать это, кроме написания моего собственного препроцессора? Нет, что было бы хорошим началом в изучении, как написать один? (Использование MinGW с Code :: Blocks).

0

Решение

Обычный способ сделать подобные вещи — объявить функции в заголовочном файле с помощью специального макроса. Этот макрос будет определяться по-разному в зависимости от того, в какой исходный файл он включен. Обычно он просто определяет стандартный прототип функции, но при включении в специальный исходный файл он будет определяться для добавления записей в таблицу.

Что-то вроде этого:

// functions.h
#ifndef FUNCTION_H_
#define FUNCTION_H_

#ifndef FUNCTION
# define FUNCTION(name) \
void name(const std::vector<std::string> &);
#endif

FUNCTION(foo)
FUNCTION(bar)

#endif

// functions.cpp
// File that defines the function table

#include <functional>

using function_type = std::function<void(const std::vector<std::string> &)>;

#define FUNCTION(name) \
{ #name, name },

std::map<std::string, function_type> functions = {
#include "functions.h
};

Теперь у вас есть std::map содержит указатели на функции, проиндексированные по имени функции.

Да, вы все еще должны поддерживать «список» своих функций, а именно список прототипов в functions.h, но когда вы добавляете (или удаляете) функции, очень легко «изменить» этот список.

3

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

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

Одним из возможных решений было бы использование переопределения и повторного включения в качестве техники X-Macros:

#define CONSOLE_COMMAND(a,body) \
void a(some_arguments) body

CONSOLE_COMMAND(my_command, { ... })

const char *array[] = {
#undef CONSOLE_COMMAND
#define CONSOLE_COMMAND(a,body) #a ,
#include __FILE__
};

Более идиоматическим решением C ++ будет иметь ваши команды в качестве объектов области файла, конструкторы которых регистрируют их во время запуска программы.

0