Почему с переменным макросом происходит сбой с ожидаемым первичным выражением перед маркером ')', если ему не предшествует именованный аргумент? - PullRequest
0 голосов
/ 30 мая 2019

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

Ниже приведена минимальная версия кода того, что я делаю.Сбой только TraceTest () без аргументовЯ также попытался создать промежуточный макрос, который передает фиктивный первый аргумент в TraceTest1, но это тоже не удается.

template<typename ...Args>
inline void f(const char*, Args&&... args) { }

#define TraceTest1(a, args...) f("Trace Start ", ##args)
#define TraceTest(args...) f("Trace Start", ##args)

TraceTest();     // error: expected primary-expression before ‘)’ token
TraceTest("a");  // works
TraceTest1();    // works
TraceTest1("a"); // works

Я прочитал документы gnu по макросам с переменными значениями, но не смог найти ничего, что могло бы объяснить это.

Я использую gcc 7.4.0 под Ubuntu 18.04 и компилирую с

g++ -Wall -Wextra -std=c++17 src/event.cpp -obin/event

1 Ответ

1 голос
/ 30 мая 2019

TraceTest() расширяется до f("Trace start",), что, очевидно, является синтаксической ошибкой.

И именованные параметры макроса variadic, и вставка маркера ',' и параметров макропарата variadic не являются стандартным C ++ (хотя каждый компилятор, который я могу найти, реализует последний). Если вы хотите их с GCC, используйте «-std = gnu ++ 17» вместо «-std = c ++ 17».


Обратите внимание, что в C ++ 20 добавлен новый токен препроцессора __VA_OPT__, который можно использовать для этого в портативном режиме:

#define TraceTest(...) f("Trace Start " __VA_OPT__(,) __VA_ARGS__)

Демонстрационная версия

__VA_OPT__ заменяется своими параметрами только в том случае, если __VA_ARGS__ не пусто, поэтому TraceTest() будет заменено на f("Trace Start ").

...