Я пытаюсь создать макрос для замены определения функции. Этот макрос должен регистрировать имя функции в некотором массиве, чтобы другой макрос мог что-то делать с элементами массива.
Я хотел бы сделать это, чтобы получить список функций, которые можно использовать в консоли, без необходимости редактировать список всякий раз, когда я добавляю новую функцию (это фактически несколько списков).
Прочитав немного, я взглянул на препроцессор 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).
Обычный способ сделать подобные вещи — объявить функции в заголовочном файле с помощью специального макроса. Этот макрос будет определяться по-разному в зависимости от того, в какой исходный файл он включен. Обычно он просто определяет стандартный прототип функции, но при включении в специальный исходный файл он будет определяться для добавления записей в таблицу.
Что-то вроде этого:
// 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
, но когда вы добавляете (или удаляете) функции, очень легко «изменить» этот список.
Препроцессор не предназначен для переопределения символов, поэтому вы не можете использовать его для накопления значения при передаче через файл.
Одним из возможных решений было бы использование переопределения и повторного включения в качестве техники 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 ++ будет иметь ваши команды в качестве объектов области файла, конструкторы которых регистрируют их во время запуска программы.