Почему этому макросу передаются три аргумента?

#include <vector>

struct Foo { int a, b, c; };

int main()
{
Foo myFoo = Foo{ 1, 2, 3 };

std::vector<Foo> listOfFoos;
listOfFoos.push_back(Foo{ 1, 2, 3 });#define push(x) listOfFoos.push_back(x)

push(Foo{ 1, 2, 3 } ); // Error

}

Ошибки:

> "Expected a '}'"> "Syntax error: expected a ')' not '}'"  "Syntax
> error: missing ')' before ';'"

Мне потребовались целые годы в Visual Studio, чтобы попытаться выяснить, что происходит. Только когда я скомпилировал на онлайн-компиляторе, используя GCC, я получил более описательную ошибку:

ошибка: макрос «push» передал 3 аргумента, но принимает только 1

Я думаю, я запутался, потому что я думал, что std :: initializer_list — это одна структура, и она должна быть передана как одна. Когда он жалуется, что 3 аргумента передаются макросу, он говорит, что делает push ({1, 2, 3}); Я делаю эквивалент толчка (1, 2, 3);? Казалось бы, std :: initializer_list выполняет тип раскрытия своих элементов перед этапом предкомпиляции, когда он разрешает макрос. Я не понимаю, почему это так. Кроме того, я попытался обернуть его в другой набор скобок, и это работает:

push( ( {1, 2, 3} ) );

1

Решение

Макросы очень примитивны и ограничены, они (не обязательно) ничего не знают о языке программирования, в котором они используются.

Предположим, у вас есть макрос

#define foo(x, y, z)

и использовать его как foo(1, 2, 3), Препроцессор разделяется запятой (,) и устанавливает переменные x, y, а также z в соответствии с введенными числами. В вашем макро-вызове, push(Foo{ 1, 2, 3 } ), это не отличается. Он разделяется на запятую и устанавливает x в Foo{ 1, Тем не менее, есть еще два значения, 2 а также 3 }отсюда и ошибка. Фигурные скобки не особенный в любом случае для препроцессора это просто еще одно письмо.

Чтобы просто пройти все через, вместо одного аргумента, возьмите его как va-args:

#define push(...) listOfFoos.push_back(__VA_ARGS__)

где ... средства, если есть что-то лишнее, просто возьми а также __VA_ARGS__ средства расширить на все, что вы получили дополнительно.

Подсказка: всегда приятно иметь вкладку godbolt.org с установленными флагами компилятора -E открыть, чтобы проверить расширение макроса. пример

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]