在C++ 11中应该首先发生什么:原始字符串扩展还是宏?

sta*_*ole 42 c++ rawstring c-preprocessor c++11

此代码适用于Visual C++ 2013,但不适用于gcc/clang:

#if 0
R"foo(
#else
int dostuff () { return 23; }
// )foo";
#endif
dostuff();
Run Code Online (Sandbox Code Playgroud)

Visual C++首先删除if 0.Clang首先扩展R原始字符串(并且永远不会定义dostuff).谁是对的,为什么?

Ton*_*roy 36

[更新:Adrian McCarthy在下面评论说MSVC++ 2017修复此问题]

GCC和clang是对的,VC++是错误的.

2.2翻译阶段[lex.phases]:

[...]

  1. 源文件被分解为预处理标记(2.5)和空白字符序列(包括注释).

  2. 执行预处理指令,[...]

并且在令牌中列出了2.5个预处理令牌[lex.pptoken]string-literals.

因此,首先需要解析来标记字符串文字,"消耗" #elsedostuff函数定义.

  • @starmole:很多旧的编译器曾经做过很多像这样的错误,但是MS VC++特别突出用于很少修复这样的事情,因为他们不想冒险破坏为编译器编写的大量代码.以某种方式依赖现有的行为. (12认同)
  • 要添加到@TonyD:*特别是*在奇怪的边缘情况下,人们不太可能遇到. (2认同)
  • MSVC++ 2017似乎做对了.原始字符串文字在MSVC++ 2013中是全新的.MSVC预处理器长期存在一些非标准行为,这些行为保持原样以便向后兼容.但最近甚至预处理器也正在接受标准合规处理.https://blogs.msdn.microsoft.com/vcblog/2018/07/06/msvc-preprocessor-progress-towards-conformance/ (2认同)