Разрешение списков инициализатора внутри макроса - PullRequest
1 голос
/ 23 декабря 2019

В проекте, над которым я работал, есть макрос, который записывает выражение. Мне было поручено добавить возможность передавать в него несколько значений и получать каждый отпечаток отдельно.
Мне удалось сравнительно легко работать с 1-5 аргументами. Он даже отлично работает, будучи переданным в функцию.

Проблема, с которой я столкнулся сейчас, состоит в том, что списки инициализатора больше не работают. В проекте использовались переменные аргументы для инициализации массива внутри него, например func(std::vector<int>{0, 1, 0, 1}). Так как я реализовал много arg, это больше не работает из-за запятых.

Я знаю, что могу сделать func((std::vector<int>{0, 1, 0, 1})), и это будет прекрасно работать, но я знаю, что это не понравится в качестве обходного решения. Есть ли способ заставить их работать без дополнительных скобок или добавить дополнительные скобки при необходимости?

Вот некоторые соответствующие фрагменты:


// Intermediate macro "chooser"
#define func_x(x, A, B, C, D, E, Func, ...) Func

// Macro to be called and used by user
// First param must be blank to allow for 0 argument function
#define func(...) func_x(, ##__VA_ARGS__, \
  func_5(__VA_ARGS__), func_4(__VA_ARGS__), func_3(__VA_ARGS__), \
  func_2(__VA_ARGS__), func_1(__VA_ARGS__), func_0())

// Macros for 1 through 5 args, calls the func_VA macro.
#define func_1(A1) func_VA(A1)
#define func_2(A1, A2) func_1(A1), func_VA(A2)
#define func_3(A1, A2, A3) func_2(A1, A2), func_VA(A3)
#define func_4(A1, A2, A3, A4) func_3(A1, A2, A3), func_VA(A4)
#define func_5(A1, A2, A3, A4, A5) func_4(A1, A2, A3, A4), func_VA(A5)

// Prints expression and type
// We use a variadic macro to support commas inside expressions (e.g.
// initializer lists):
#define func_VA(...)                                                  \
  func_macro::DebugOutput(__FILE__, __LINE__, __func__, #__VA_ARGS__) \
      .print(func_macro::type_name<decltype(__VA_ARGS__)>(), (__VA_ARGS__))

func(std::vector<int>{0, 1, 0, 1});
// Errors

func((std::vector<int>{0, 1, 0, 1}));
// Works, but also prints the () when logging so not ideal. Better than nothing though.

У меня естьпытался установить скобки вокруг определенных частей моих макросов, чтобы попытаться исправить это, но безрезультатно. Как #define func_1(A1) func_VA((A1)) или аналогичный.

РЕДАКТИРОВАТЬ: я добился некоторого прогресса

Объявление func_1 как #define func_1(...) func_VA(__VA_ARGS__) теперь работает, если я вызываю func_1(std::vector<int>{0, 1, 0, 1});, как вы можете предположить.

Я создал макрос «обертка», который возвращает (__VA_ARGS__), и это позволяет макросу корректно работать со списком init, хотя строковая версия имеет дополнительные скобки. Хотя я не могу заставить это работать таким образом, чтобы вам (как пользователю) не приходилось вызывать оболочку для ваших массивов (что сложнее, чем ставить скобки на место).

1 Ответ

0 голосов
/ 23 декабря 2019

Если вы можете изменить DebugOutput::print на шаблон переменной, вы можете сделать что-то вроде:

#define func(...)                                                     \
  func_macro::DebugOutput{__FILE__, __LINE__, __func__, #__VA_ARGS__} \
      .print(__VA_ARGS__)


namespace func_macro
{

struct DebugOutput
{
    const char* filename = nullptr;
    int line = 0;
    const char* funcname = nullptr;
    const char* argsString = nullptr;

    template <typename ... Ts>
    void print(const Ts&... args) const
    {
        std::cout << filename << ":" << line << " in " << funcname << std::endl;
        std::cout << "func(" << argsString << ")\n";

        ((std::cout << typeid(args).name() << ": " << args << std::endl), ...);
    }
};

}

Демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...