为什么不能使用宏来使用C++ 11大括号初始化?

Bar*_*ett 4 c++ c++11

我刚刚发现,在将参数传递给宏时,不能总是使用大括号初始化.当ASSERT()宏无法编译时,我发现了这一点.但是,以下示例说明了此问题:

#include <iostream>
#include <string>
using namespace std;

#define PRINT_SIZE( f ) cout << "Size=" << (f).size() << endl;

int main()
{
  PRINT_SIZE( string("ABC") );  // OK, prints: "Size=3"
  PRINT_SIZE( string{"ABC"} );  // OK, prints: "Size=3"

  PRINT_SIZE( string("ABCDEF",3) ); // OK, prints: "Size=3"
  PRINT_SIZE( string{"ABCDEF",3} ); // Error: macro 'PRINT_SIZE' passed 2 arguments, but takes just 1

   return 0;
}
Run Code Online (Sandbox Code Playgroud)

有没有理由不能使大括号初始化使用宏?

编辑:

我后来发现你也可以使用一个可变参数宏,这完全解决了这个问题:

#include <iostream>
#include <string>
using namespace std;

#define PRINT_SIZE( ... ) cout << "Size=" << (__VA_ARGS__).size() << endl;

int main()
{
  PRINT_SIZE( string("ABC") );  // OK, prints: "Size=3"
  PRINT_SIZE( string{"ABC"} );  // OK, prints: "Size=3"

  PRINT_SIZE( string("ABCDEF",3) ); // OK, prints: "Size=3"
  PRINT_SIZE( string{"ABCDEF",3} ); // OK, prints: "Size=3"

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

Win*_*ute 14

该列表分为几个宏参数.当你写作

PRINT_SIZE( string{"ABCDEF",3} );
Run Code Online (Sandbox Code Playgroud)

这会尝试PRINT_SIZE使用两个参数(一个string{"ABCDEF"和一个)来扩展宏,这两个参数3}都会失败.在许多情况下(包括你的)可以通过添加另一对括号来解决这个问题:

PRINT_SIZE( (string{"ABCDEF",3}) );
Run Code Online (Sandbox Code Playgroud)

这些括号可以防止参数的分裂,因此可以PRINT_SIZE使用单个参数进行扩展(string{"ABCDEF",3})(请注意,括号是参数的一部分).

  • 我认为对这个问题的有益讨论会比大量的SO评论更长.这是一个想法,但我想知道有多少现有代码会被更改破坏 - 目前,大括号可以简单地作为宏参数传递.它不仅仅涉及大括号 - 例如,考虑`SOME_MACRO(std :: is_same <A,B> :: value)`. (4认同)
  • @Barnett,预处理器的变化不太顺利.许多人更希望预处理器从一个功能中过时,该功能至少取代其功能而不包含宏中的所有不良内容.AFAIK,预处理器与C99完全相同,减去了一些与C和C++有关的小事情,而不是预处理器本身. (3认同)

cma*_*ter 7

是的,有一个原因:预处理器不知道大括号.它只尊重字符串文字和括号,对其他C/C++语言结构它是无知的.就这样,电话

PRINT_SIZE( string{"ABCDEF",3} );
Run Code Online (Sandbox Code Playgroud)

被解析为具有两个参数的宏调用string{"ABCDEF"3}.由于宏PRINT_SIZE()只需要一个参数,因此预处理器可以解决问题.请注意,此时甚至没有调用C++编译器!