#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} ) );
Макросы очень примитивны и ограничены, они (не обязательно) ничего не знают о языке программирования, в котором они используются.
Предположим, у вас есть макрос
#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
открыть, чтобы проверить расширение макроса. пример
Других решений пока нет …