繁体   English   中英

具有可变参数的嵌套宏确实可以在GCC中进行编译,但不能在MSVC中进行编译

[英]Nested macro with variadic arguments does compile in GCC but not in MSVC

我使用boost / preprocessor创建了一个宏来重复创建代码。 原因是我使用非常受限制的编译器在非常受限制的目标硬件上工作,该编译器不支持数组。

我想出的代码如下:

# 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查询。

我在gcc的godbolt上测试了此代码,就像在这里看到的那样,它的工作就像一个魅力。 现在,当我在MSVC中尝试相同操作时,它不会编译。 错误为C2065,例如未声明“ variableName”。 在Godbolt上看到它

这是为什么? 这是MSVC中的错误吗? MSVC是否仅不支持这些类型的宏? 我的代码中有错误吗?

我的调查使我相信这是MSVC中的错误。

如果我将代码更改为以下内容并进行预处理(请注意,我的“ coord”和“ variableName”,“ otherVariableName”标识符只是为了使代码的这些部分匹配某些内容,请注意我如何将其反转) #if 0将您的IF_BODY和IF_BODY_以及该IF_BODY_注释掉):

#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.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; }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM