С++ макрос и лямбда-захват

При использовании лямбда-выражения в макросе с несколькими захватами возникает одна из следующих ошибок (Visual Studio 2017) :
Error C2143 syntax error: missing ']' before ';'
Error C2958 the left bracket '['

Как я могу избежать этой ошибки?

Пример кода:

#include <functional>
#include <iostream>

#define MYMACRO(lambda) lambda

int main()
{
    int a = 13;
    int b = 37;
    auto lambda = MYMACRO([a, b]() { std::cout << a << b << std::endl; });
    lambda();
    return 0;
}

person Antoine    schedule 13.04.2018    source источник
comment
Вам действительно нужны макросы? Мне никогда не приходилось использовать их в течение длительного времени.   -  person Jens    schedule 13.04.2018


Ответы (2)


Как отмечалось в другом месте, фактическая ошибка заключается в том, что MYMACRO в том виде, в каком она написана, ожидает только один аргумент. Если они не заключены в круглые скобки или кавычки, запятые используются для разделения отдельных аргументов вызова макроса.

Лямбда может иметь несколько запятых в квадратных скобках, поэтому MYMACRO на самом деле должна иметь возможность обрабатывать переменные аргументы, если вы хотите оставить синтаксис вызова таким же, как в вашей программе. Это возможно, начиная с C++11, в котором добавлена ​​поддержка вариативных макросов.

Visual Studio 2017 поддерживает синтаксис вариативного макроса. Итак, вы можете изменить свой макрос на:

#define MYMACRO(...) __VA_ARGS__

Обратите внимание, что переменные аргументы могут появляться только в конце спецификации аргументов макроса.

person jxh    schedule 13.04.2018

GCC выдает немного более дружественное сообщение об ошибке:

10:73: ошибка: макрос "МАЙМАКРО" передал 2 аргумента, а принимает всего 1

Запятые в вашей лямбда-декларации интерпретируются как разделители аргументов макроса. Вам нужно заключить выражение в скобки:

#include <functional>
#include <iostream>

#define MYMACRO(lambda) lambda

int main()
{
    int a = 13;
    int b = 37;
    auto lambda = MYMACRO(([a, b]() { std::cout << a << b << std::endl; }));
    lambda();
    return 0;
}

Visual Studio выдает предупреждение, а затем игнорирует ложные аргументы макроса, поэтому ваш код эквивалентен:

auto lambda = MYMACRO([a);

Что делает сообщение об ошибке более понятным. См. https://docs.microsoft.com/en-gb/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4002

person Alan Birtles    schedule 13.04.2018
comment
Спасибо. Похоже на плохую интерпретацию составителями лямбда-захвата в макросе? Как вы думаете, это поведение будет исправлено? Или будет упорствовать? - person Antoine; 13.04.2018
comment
Компиляторы делают именно то, что им нравится, передача дополнительных параметров в макрос является неопределенным поведением. - person Alan Birtles; 13.04.2018
comment
Компиляторам разрешено игнорировать недопустимый код, если они выдают какую-либо диагностическую ошибку, поэтому Visual Studio не является неверным, см. stackoverflow.com/questions/5248599/ - person Alan Birtles; 13.04.2018