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
) может состоять из нуля или более аргументов.