Variadic макро предупреждение

В C++, variadic макросы require at least one argument for the '...', Рассмотрим функцию: FOO(a, b, ...); Что мне делать, если я хочу, чтобы оба этих вызова были правильными и без предупреждений? FOO(5, 4, "gamma"); FOO(5, 4); Я использую --pedantic флаг, так что просто подавление предупреждения не вариант.

Второй дает предупреждение во время компиляции, упомянутое выше. Я считал это:

Изменение определения на FOO(a, ...); и расщепление __VA_ARGS__ переменная (что означает...) в b и, если присутствует, в остальное. Таким образом, вызовы функций будут выглядеть так: FOO(5, "4gamma"); а также FOO(5, "4"); Это, я думаю, не очень хороший вариант, потому что расщепление неэффективно и объявление функции не потребует b аргумент, хотя его обязательный.

Есть ли лучшие способы получить компиляцию без предупреждений?

3 ответа

Решение

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

Изменение определения на FOO(a, ...); и расщепление __VA_ARGS__ переменная (что означает...) в b и, если присутствует, в остальное.

Да.

Таким образом, вызовы функций будут выглядеть так: FOO(5, "4gamma"); а также FOO(5, "4");

Нет. Продолжить вызов как FOO(5, 4, "gamma"); а также FOO(5, 4);, В первом случае __VA_ARGS__ является 4, "gamma", Во втором случае __VA_ARGS__ является 4,

Если вам нужно извлечь , "gamma" из первого, что может быть сделано препроцессором. Требуется верхний предел количества параметров, но вы можете увеличить его практически до любого числа, которое вам нравится. Хотя это некрасиво.

Если __VA_ARGS__ не содержит запятых, извлечение тривиально:

#define COMMA_TRAILING_ARGS_0(a)

Если вы знаете __VA_ARGS__ содержит хотя бы одну запятую, вы можете использовать

#define COMMA_TRAILING_ARGS_1(a, ...) , __VA_ARGS__

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

#define ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) _16
#define HAS_COMMA(...) ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, )

Комбинированный:

#define COMMA_TRAILING_ARGS_0(a)
#define COMMA_TRAILING_ARGS_1(a, ...) , __VA_ARGS__

#define ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) _16
#define HAS_COMMA(...) ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,)

#define CONCAT(a, b) a ## b
#define CONCAT_(a, b) CONCAT(a, b)

#define FOO(a, ...) BAR(a CONCAT_(COMMA_TRAILING_ARGS_, HAS_COMMA(__VA_ARGS__)) (__VA_ARGS__))

FOO(5, 4, x, q);    // expands to BAR(5, x, q);
FOO(5, 4, "gamma"); // expands to BAR(5, "gamma");
FOO(5, 4);          // expands to BAR(5);
  • Вы можете избавиться от этого макроса, потому что макросы злые и заменить его шаблоном или чем-то еще
  • Вы можете определить два макроса: FOOs - со многими аргументами и FOO - всего с двумя аргументами
  • Вы можете использовать GCC ##__VA_ARGS__ расширение (при условии, что вы используете gcc или совместимый компилятор)

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

void foo(int, int);
void foo(int, int, const std::string&);

foo(3, 4); // calls first
foo(3, 4, "hello"); // calls second

Или, может быть, даже:

void foo(int, int, const std::string& = "");

С другой стороны, если вы можете использовать C++11:

template<typename... Args>
void foo(int, int, const Args&... args); // google variadic templates

Пакет параметров (args) может состоять из нуля или более аргументов.

Другие вопросы по тегам