简体   繁体   English

c++ 递归宏无法在 MSVC 上编译?

[英]c++ recursive macro wont compile on MSVC?

I got this source code from [https://www.scs.stanford.edu/~dm/blog/va-opt.html].我从 [https://www.scs.stanford.edu/~dm/blog/va-opt.html] 获得了这个源代码。 Using MSVC with C++20 it doesn't compile, but it does compile on other compilers.将 MSVC 与 C++20 一起使用不会编译,但会在其他编译器上编译。 Why?为什么? And how can I fix that?我该如何解决?

`/* compile with:
   c++ -std=c++20 -Wall -Werror make_enum.cc -o make_enum
 */

#include <iostream>

#define PARENS ()

// Rescan macro tokens 256 times
#define EXPAND(arg) EXPAND1(EXPAND1(EXPAND1(EXPAND1(arg))))
#define EXPAND1(arg) EXPAND2(EXPAND2(EXPAND2(EXPAND2(arg))))
#define EXPAND2(arg) EXPAND3(EXPAND3(EXPAND3(EXPAND3(arg))))
#define EXPAND3(arg) EXPAND4(EXPAND4(EXPAND4(EXPAND4(arg))))
#define EXPAND4(arg) arg

#define FOR_EACH(macro, ...)                                    \
  __VA_OPT__(EXPAND(FOR_EACH_HELPER(macro, __VA_ARGS__)))
#define FOR_EACH_HELPER(macro, a1, ...)                         \
  macro(a1)                                                     \
  __VA_OPT__(FOR_EACH_AGAIN PARENS (macro, __VA_ARGS__))
#define FOR_EACH_AGAIN() FOR_EACH_HELPER

#define ENUM_CASE(name) case name: return #name;

#define MAKE_ENUM(type, ...)                    \
enum type {                                     \
  __VA_ARGS__                                   \
};                                              \
constexpr const char *                          \
to_cstring(type _e)                             \
{                                               \
  using enum type;                              \
  switch (_e) {                                 \
  FOR_EACH(ENUM_CASE, __VA_ARGS__)              \
  default:                                      \
    return "unknown";                           \
  }                                             \
}

MAKE_ENUM(MyType, ZERO, ONE, TWO, THREE);

void
test(MyType e)
{
  std::cout << to_cstring(e) << " = " << e << std::endl;
}

int
main()
{
  test(ZERO);
  test(ONE);
  test(TWO);
  test(THREE);
}

/*
  Local Variables:
  c-macro-pre-processor: "c++ -x c++ -std=c++20 -E -"
  End:
*/`

I cant figure out for the life of me what the problem is.我无法弄清楚我的生活是什么问题。 I've tried modifying the code, to me it seems that __VA_ARGS__ isn't accepted when it should be, or that it can't accept the way the macros are ordered.我试过修改代码,对我来说似乎__VA_ARGS__在应该被接受的时候没有被接受,或者它不能接受宏的排序方式。 Here are the errors:以下是错误:

1>make_enum.cc
1>C:\Users\Thomas\source\repos\outoftouch\outoftouch\make_enum.cc(40,1): warning C4003: not enough arguments for function-like macro invocation 'FOR_EACH_HELPER'
1>C:\Users\Thomas\source\repos\outoftouch\outoftouch\make_enum.cc(40,1): warning C4003: not enough arguments for function-like macro invocation 'ENUM_CASE'
1>C:\Users\Thomas\source\repos\outoftouch\outoftouch\make_enum.cc(40,1): error C2059: syntax error: 'case'
1>C:\Users\Thomas\source\repos\outoftouch\outoftouch\make_enum.cc(40,1): error C2065: 'ENUM_CASE': undeclared identifier
1>C:\Users\Thomas\source\repos\outoftouch\outoftouch\make_enum.cc(40,1): error C3861: 'FOR_EACH_HELPER': identifier not found
1>C:\Users\Thomas\source\repos\outoftouch\outoftouch\make_enum.cc(40,1): error C2059: syntax error: ')'
1>C:\Users\Thomas\source\repos\outoftouch\outoftouch\make_enum.cc(40,1): error C2146: syntax error: missing ';' before identifier 'default'
1>C:\Users\Thomas\source\repos\outoftouch\outoftouch\make_enum.cc(40,1): warning C4065: switch statement contains 'default' but no 'case' labels
1>Done building project "outoftouch.vcxproj" -- FAILED.

The old preprocessor in MSVC is known to contain many problems, see eg this article by Microsoft.众所周知,MSVC 中的旧预处理器包含许多问题,请参见 Microsoft 的这篇文章 Their new preprocessor can be used via the /Zc:preprocessor flag, causing the preprocessor to be more standard conform and also closer to what other major compilers do.他们的新预处理器可以通过/Zc:preprocessor标志使用,使预处理器更符合标准,也更接近其他主要编译器所做的。

In this specific case, I think the problem is that the old preprocessor incorrectly expands FOR_EACH_AGAIN in FOR_EACH_HELPER early;在这种特定情况下,我认为问题在于旧的预处理器在FOR_EACH_HELPER FOR_EACH_AGAIN it shouldn't, because it is not followed by parentheses.它不应该,因为它后面没有括号。 Compare the corresponding section "Rescanning replacement list for macros" in the above mentioned article .比较上述文章中的相应部分“重新扫描宏的替换列表” The warning "not enough arguments for function-like macro invocation 'FOR_EACH_HELPER'" also hints at that.警告"not enough arguments for function-like macro invocation 'FOR_EACH_HELPER'"也暗示了这一点。

With /Zc:preprocessor , the code compiles without issues.使用/Zc:preprocessor ,代码编译没有问题。 Example on godbolt . godbolt的例子。

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

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