带有可变参数的嵌套宏在GCC中编译,但在MSVC中不编译
Nested macro with variadic arguments does compile in GCC but not in MSVC
我用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查询。
我用gcc在godbolt上测试了这段代码,它的工作原理就像一个魅力,正如您在这里看到的那样。现在,当我在MSVC中尝试同样的操作时,它不会编译。错误为C2065,例如未声明"variableName"。在godbolt上看到它。
为什么?这是MSVC中的一个错误吗?MSVC中是否不支持这些类型的宏?我的代码中有错误吗?
我的调查让我相信这是MSVC中的一个错误。
如果我将代码更改为以下内容,并对文件进行预处理(请注意,我的"coord"answers"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)
}
请注意,宏调用具有正确数量的参数。但是,如果我将#if0更改为#if1,我将得到以下编译器输出: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的所有内容都被分配给"condition",而不是被分解为正确的IF_BODY_参数。我将通过MSVS帮助->发送反馈->报告问题机制将此作为反馈提交。
--
好吧,我已经设法找到了一个解决方案,但它非常丑陋。它需要对BOOST _PP_REPEAT家族进行可变扩展(我在这里只部分实现了它)。作为boost的一个建议,这可能值得提交,但我不确定boost.preprrocessor是否仍在维护。请注意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; }
}
- 为什么 gcc 编译这个而 msvc 没有
- std::unique_ptr 在 GCC 中工作,但不能在 Visual Studio 中编译
- GCC,CMake,预编译标头和维护依赖项
- GCC 8.3 无法编译 std::bind_front
- Clang不会编译GCC会编译的模板专业化
- 使用交叉工具ng编译gcc时出错
- 编译 GCC-5.0 OS X 狮子 dyld:找不到符号:__ZNKSt11logic_error4whatEv
- 在类中将不完整类型的unique_ptr初始化为 nullptr 时编译 gcc 错误
- 除了 Linux 上的源代码和编译 (GCC) 之外,有没有办法在 Windows 中托管 IDE
- 在 64 位 debian 上编译 GCC 的代码可视化补丁
- 编译gcc 4.6.4中的boost::move
- 模板编译:gcc vs VS2010
- C++ 使用编译器编译"gcc"简单文件
- 如何从php编译GCC
- 在 Visual Studio 中编译 gcc 代码会导致错误 C3646:"__attribute__":未知的覆盖说明符
- 在windows上编译gcc 4.7
- 在Vortex86DX上从头开始构建和编译GCC 5.2.0时出错
- 在编译GCC时出错部分模板专门化,而不是MSVC
- GLM Math lib 编译 GCC 错误
- Synology交叉编译GCC -std=c++0x