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

时间:2015-04-11 14:17:30

标签: 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;
}

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

修改

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

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

3 个答案:

答案 0 :(得分:13)

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

PRINT_SIZE( string{"ABCDEF",3} );

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

PRINT_SIZE( (string{"ABCDEF",3}) );

这些括号阻止了参数的拆分,因此PRINT_SIZE扩展为一个参数(string{"ABCDEF",3})(注意括号是参数的一部分)。

答案 1 :(得分:7)

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

PRINT_SIZE( string{"ABCDEF",3} );

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

答案 2 :(得分:0)

这个怎么样?

#define SOME_BRACE  \
{                   \
    6, 8, 1, 3, 7,  \
    1, 4, 2, 0, 9   \
}

#define BRACE_SIZE(brace) (sizeof((int[]) SOME_BRACE) / sizeof(int))

int main(int argc, char *argv[])
{
    int array[BRACE_SIZE(SOME_BRACE)] = SOME_BRACE, i, s;

    for (i = 0, s = 0; i < BRACE_SIZE(SOME_BRACE); i++) {
        s = s + array[i];
    }
    /* 41 is expected */
    return s;
}