Мое расследование заставляет меня поверить, что это ошибка в 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; }
}