Вложенный макрос с переменными аргументами компилируется в GCC, но не в MSVC - PullRequest
0 голосов
/ 27 апреля 2019

Я создал макрос с boost / препроцессором для повторного создания кода.Причина этого в том, что я работаю на очень ограниченном целевом оборудовании с очень ограниченным компилятором, который не поддерживает массивы.

Код, который я придумал, следующий:

# define ESC(...) __VA_ARGS__
# define IF_BODY(n, condition, lhs, rhs, arg1, arg2) \
if (condition > n) { \
    lhs##n.arg1 = rhs[n].arg1; \
    lhs##n.arg2 = rhs[n].arg2; \
}
# define IF_BODY_(A, B) IF_BODY(A, B)
# define IF_QUERY(z, n, vars) IF_BODY_(n, ESC vars)

BOOST_PP_REPEAT(3, IF_QUERY, \
        (index, variableName, otherVariableName, latitude, longitude))

Его цель - создать несколько запросов if с возрастающими условиями.

Я тестировал этот код на Godbolt с помощью gcc, и он работает как чудо, как вы можете см. Здесь .Теперь, когда я пытаюсь сделать то же самое в MSVC, он не компилируется.Ошибка C2065, например, «variableName» не объявлено. Смотрите здесь, на Годболте .

Почему это так?Это ошибка в MSVC?Эти типы макросов просто не поддерживаются в MSVC?Есть ли ошибка в моем коде?

1 Ответ

1 голос
/ 27 апреля 2019

Мое расследование заставляет меня поверить, что это ошибка в MSVC.

Если я изменю код на следующий и сделаю предварительную обработку в файл (обратите внимание, что мои идентификаторы'ordinate 'и' variableName ', otherVariableName' просто для того, чтобы эти части кода соответствовали чему-либо, и обратите внимание на то, как Я поменял ваши IF_BODY и IF_BODY_ и IF_BODY_ закомментирован #if 0):

#include <boost/preprocessor/repeat.hpp>

struct coord
{
    int latitude, longitude;
};

# define ESC_(...) __VA_ARGS__
#define ESC(vars) ESC_ vars

#if 0
# define IF_BODY_(n, condition, lhs, rhs, arg1, arg2) \
if (condition > n) { \
    lhs##n.arg1 = rhs[n].arg1; \
lhs##n.arg2 = rhs[n].arg2; \
}
#endif

# define IF_BODY(A, B) IF_BODY_(A, ESC(B))

# define IF_QUERY(z, n, vars) IF_BODY(n, vars)

int main()
{
    int index;
    coord variableName0, otherVariableName0;
    coord variableName1, otherVariableName1;
    coord variableName1, otherVariableName1;
    BOOST_PP_REPEAT(3, IF_QUERY, (index, variableName, otherVariableName, latitude, longitude))
}

Я получаю следующее:

int main()
{
    int index;
    coord variableName0, otherVariableName0;
    coord variableName1, otherVariableName1;
    coord variableName1, otherVariableName1;
    IF_BODY_(0, index, variableName, otherVariableName, latitude, longitude)
    IF_BODY_(1, index, variableName, otherVariableName, latitude, longitude)
    IF_BODY_(2, index, variableName, otherVariableName, latitude, longitude)
}

Обратите внимание, что вызов макроса имеет правильное количество аргументов. Однако, если я изменю #if 0 на #if 1, я получу следующий вывод компилятора: tester \ tester.cpp (35): предупреждение C4003: недостаточно аргументов для функционально-подобного вызова макроса 'IF_BODY _'

Глядя на предварительно обработанные результаты в этом случае:

int main()
{
    int index;
    coord variableName0, otherVariableName0;
    coord variableName1, otherVariableName1;
    coord variableName1, otherVariableName1;
    if (index, variableName, otherVariableName, latitude, longitude > 0) { 0. = [0].; 0. = [0].; } 
    if (index, variableName, otherVariableName, latitude, longitude > 1) { 1. = [1].; 1. = [1].; } 
    if (index, variableName, otherVariableName, latitude, longitude > 2) { 2. = [2].; 2. = [2].; }
}

Кажется, что MSVC выполняет назначение макропеременных перед выполнением расширения ESC, что все содержимое B присваивается «условию», а не разбивается на правильные аргументы IF_BODY_. Я отправлю это в качестве отзыва через справку MSVS -> Отправить отзыв -> Сообщить о проблеме механизма.

-

Хорошо, мне удалось найти решение, но оно очень безобразно. Это требует вариативного расширения семейства BOOST_PP_REPEAT (которое я только частично реализовал здесь). Возможно, стоит представить это как предложение для boost, но я не уверен, что boost.preprocessor все еще поддерживается. И обратите внимание, что макросы ESC_ / ESC просто исчезли в этой версии.

#include <boost/preprocessor/repeat.hpp>

# define BOOST_PP_REPEAT_1_1_V(m, d, ...) m(2, 0, d, __VA_ARGS__)
# define BOOST_PP_REPEAT_1_2_V(m, d, ...) BOOST_PP_REPEAT_1_1_V(m, d, __VA_ARGS__) m(2, 1, d, __VA_ARGS__)
# define BOOST_PP_REPEAT_1_3_V(m, d, ...) BOOST_PP_REPEAT_1_2_V(m, d, __VA_ARGS__) m(2, 2, d, __VA_ARGS__)
# define BOOST_PP_REPEAT_1_4_V(m, d, ...) BOOST_PP_REPEAT_1_3_V(m, d, __VA_ARGS__) m(2, 3, d, __VA_ARGS__)
# define BOOST_PP_REPEAT_1_I_V(c, m, d, ...) BOOST_PP_REPEAT_1_ ## c##_V(m, d, __VA_ARGS__)
# define BOOST_PP_REPEAT_1_V(c, m, d, ...) BOOST_PP_REPEAT_1_I_V(c, m, d, __VA_ARGS__)

#define BOOST_PP_REPEAT_V BOOST_PP_CAT(BOOST_PP_CAT(BOOST_PP_REPEAT_, BOOST_PP_AUTO_REC(BOOST_PP_REPEAT_P, 4)), _V)


struct coord
{
    int latitude, longitude;
};

#if 1
# define IF_BODY_(n, condition, lhs, rhs, arg1, arg2) \
if (condition > n) { \
    lhs##n.arg1 = rhs[n].arg1; \
lhs##n.arg2 = rhs[n].arg2; \
}
#endif

#define ESC_(...) __VA_ARGS__
#define ESC(a) ESC_(a)
#define IF_BODY(a, ...) ESC_(IF_BODY_(a, __VA_ARGS__))
# define IF_QUERY(z, n, ...) IF_BODY(n, __VA_ARGS__)


int main()
{
    int index = 0;
    coord variableName0, variableName1, variableName2;
    coord otherVariableName[3];

    BOOST_PP_REPEAT_V(3, IF_QUERY, index, variableName, otherVariableName, latitude, longitude)
}

новый код расширяется до:

int main()
{
    int index = 0;
    coord variableName0, variableName1, variableName2;
    coord otherVariableName[3];

    if (index > 0) { variableName0.latitude = otherVariableName[0].latitude; variableName0.longitude = otherVariableName[0].longitude; } 
    if (index > 1) { variableName1.latitude = otherVariableName[1].latitude; variableName1.longitude = otherVariableName[1].longitude; } 
    if (index > 2) { variableName2.latitude = otherVariableName[2].latitude; variableName2.longitude = otherVariableName[2].longitude; }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...