Оператор ##
выполняет точную замену токена, поэтому в этом случае он пытается отправить токен "CALL(func1, false)"
в качестве последнего аргумента функции func1
C .
Проблема в том, что CALL
- это макрос, и вы не можете вкладывать вызовы переменных макросов в список ##__VA_ARGS__
.
Причина, по которой он работает, когда внутренний макрос передается в качестве именованного аргумента, заключается в том, что препроцессор будет анализировать именованные аргументы для внутренних макросов, но не в списках ##__VA_ARGS__
, где существует простая замена токена.
Один из способов решения этой проблемы - присвоить результат внутреннего CALL
переменной-заполнителю и затем передать его макросу.
int main() {
CALL(func2, CALL(func1, false), false);
bool result = CALL(func1, false);
CALL(func2, false, result);
}
Другой способ решить эту проблему - просто использовать __VA_ARGS__
в качестве единственного аргумента функции func
, и это позволит вам передавать вызовы вложенных макросов, например:
#define CALL(func, ...) func(__VA_ARGS__)
int main() {
CALL(func2, false, CALL(func2, false, false));
}
Давайте проанализируем вашу дилемму немного подробнее:
CALL(func2, false, CALL(func1, false))
В этом конкретном вызове макроса CALL
теперь ("func2", "tmp", CALL(func1, false))
Поэтому он пытается вызвать func1
, передавая tmp
и, ну, CALL(func1, false)
.
Здесь проходит линия между препроцессором и фактическим компилятором C.
Препроцессор, как только он начинает выполнять подстановку, он выполняет синтаксический анализ, поэтому компилятор получает CALL(func1, false)
как действительную функцию C, а не как макрос, потому что компилятор не знает только о макросах препроцессор делает.