Есть ли способ использовать строковое препроцессор С++ для переменных аргументов макроса?

Мое предположение - ответ на этот вопрос - нет, но было бы здорово, если бы был способ. Чтобы уточнить, предположим, что у меня есть следующий макрос:

#define MY_VARIADIC_MACRO(X...) // Does some stuff here in the macro definition

Что бы я хотел сделать, так или иначе выполнить строчение всех переменных X перед передачей его в вариационную функцию; ключевое слово здесь раньше. Я понимаю, что нет способа действительно получить доступ к отдельным аргументам из определения макроса, но есть ли способ скомпоновать все аргументы, возможно, что-то вроде следующего?

#define MY_VARIADIC_MACRO(X...) some_variadic_function("some string", #X)

Ответ 1

Хорошо, я не хотел отвечать на свой вопрос здесь, но я придумал достойное решение, которое представляет собой комбинацию ответа Марка Уилкинса и пример, который я дал в вопросе.

Можно сгенерировать весь набор вариационных наборов, который затем включает разделительные запятые в строке. Вот краткий пример:

#define MY_VARIADIC_MACRO(X...) printf(#X)

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

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

#define MY_VARIADIC_MACRO(X...) tokenize_my_arguments(#X)

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

* Новый материал из Edit Follows *

В комментариях к Тиму, здесь подробно рассматриваются решения. Пожалуйста, простите любые ошибки, так как это было сделано в спешке, и мне пришлось порвать с того, над чем я работаю. Кроме того, это не предназначено для копирования/вставки, поскольку оно выводит только строение аргументов для демонстрации POC, но должно быть достаточно, чтобы продемонстрировать функциональность.

Несмотря на то, что для этого решения требуется некоторое время выполнения, переменные макросы часто вызывают вариативные функции и требуют итерации через va_args, поэтому итерация происходит при поиске токенов, хотя, возможно, принесет жертву немного производительности. Тем не менее, для удобства обслуживания, универсальности и простоты внедрения это кажется лучшим вариантом на данный момент:

#define VARIADIC_STRINGIFY(_ARGUMENTS_TO_STRINGIFY...) Variadic_Stringification_Without_Variadic_Function(#_ARGUMENTS_TO_STRINGIFY)

void Variadic_Stringification_Without_Variadic_Function (const char* _stringified_arguments)
{
    strcpy(converted_arguments, _stringified_arguments);

    for(char* token = strtok(converted_arguments, ","); token != 0x0; token = strtok(0x0, ","))
        std::cout << token << std::endl;
}

Ответ 2

Вы можете использовать различные методы рекурсивного макроса для работы с переменными макросами. Например, вы можете определить макрос NUM_ARGS, который подсчитывает количество аргументов в переменном макросе:

#define _NUM_ARGS(X100, X99, X98, X97, X96, X95, X94, X93, X92, X91, X90, X89, X88, X87, X86, X85, X84, X83, X82, X81, X80, X79, X78, X77, X76, X75, X74, X73, X72, X71, X70, X69, X68, X67, X66, X65, X64, X63, X62, X61, X60, X59, X58, X57, X56, X55, X54, X53, X52, X51, X50, X49, X48, X47, X46, X45, X44, X43, X42, X41, X40, X39, X38, X37, X36, X35, X34, X33, X32, X31, X30, X29, X28, X27, X26, X25, X24, X23, X22, X21, X20, X19, X18, X17, X16, X15, X14, X13, X12, X11, X10, X9, X8, X7, X6, X5, X4, X3, X2, X1, N, ...)   N

#define NUM_ARGS(...) _NUM_ARGS(__VA_ARGS__, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

Затем с этим вы можете написать макрос FOREACH, который расширяет другой макрос для каждого элемента списка:

#define EXPAND(X)       X
#define FIRSTARG(X, ...)    (X)
#define RESTARGS(X, ...)    (__VA_ARGS__)
#define FOREACH(MACRO, LIST)    FOREACH_(NUM_ARGS LIST, MACRO, LIST)
#define FOREACH_(N, M, LIST)    FOREACH__(N, M, LIST)
#define FOREACH__(N, M, LIST)   FOREACH_##N(M, LIST)
#define FOREACH_1(M, LIST)  M LIST
#define FOREACH_2(M, LIST)  EXPAND(M FIRSTARG LIST) FOREACH_1(M, RESTARGS LIST)
#define FOREACH_3(M, LIST)  EXPAND(M FIRSTARG LIST) FOREACH_2(M, RESTARGS LIST)
        :

Это, в свою очередь, позволит вам определить свой макрос, который строит каждый из его аргументов:

#define STRINGIFY(X)    #X
#define MY_VARIADIC_MACRO(...)    FOREACH(STRINGIFY, (__VA_ARGS__))

Ответ 3

Это, вероятно, не очень близко к тому, что вы хотите, но что-то вроде следующего может привести вас туда:

#define MY_VARIADIC_MACRO(X) printf( "%s\n", #X )

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

MY_VARIADIC_MACRO ((var1, var2, "string" ));

Затем вы можете вызвать макрокоманду некоторой функцией, которая удаляет внешние парады или, возможно, анализирует данную строку.