C++宏编程终极指南:安全生成唯一变量名

92 阅读2分钟

有些时候在宏里面我们会写一些临时变量,但是由于宏里面直接写临时变量在多次使用宏时会提示定义了重复变量,这时候就想有没有办法能够让宏自动生成不重复的临时变量呢,确实可以!

// 通过定义多个宏的方式,改变宏的展开顺序,从而使__LINE__宏先展开,再进行拼接,达到自动根据行号定义一个唯一标识符的功能
#define MAKE_LABEL2(label, L) label##L
#define MAKE_LABEL1(label, L) MAKE_LABEL2(label, L)
#define UNIQUE_IDENTIFIER(label) MAKE_LABEL1(label, __LINE__)

通过以上代码就可以使用UNIQUE_IDENTIFIER()宏来根据代码所在的行号生成一个唯一的变量名,这在大多数宏里面都非常好用.以我的代码为例.我将简单的for循环写成了宏

#define FOR_I(count) const int UNIQUE_IDENTIFIER(Count) = (int)count; for (int i = 0; i < UNIQUE_IDENTIFIER(Count); ++i)

所以用的时候就直接是

FOR_I(10)
{  
    cout << "123" << endl;
}
或者在变量vectorvector<int> test{1, 2, 3};
FOR_I(test.size())
{
    cout << test[i] << endl;
}

展开就是

v2-729302faba4d28ba67767d88de749817_r.png

为什么只有那样写才能够先替换行号再替换文本拼接呢,这跟宏展开的规则有关.

宏的展开规则有两个:

  1. 参数在替换前完全展开,除非参与#或##操作.

  2. 宏展开顺序为深度优先,从左到右.

所以来看看每一步都做了什么

UNIQUE_IDENTIFIER->接收label和__LINE__

MAKE_LABEL1->传递已展开的__LINE__

MAKE_LABEL2->执行实际拼接操作

UNIQUE_IDENTIFIER(temp_var)
↓ 第一次展开(参数替换)
MAKE_LABEL1(temp_var, 42)
↓ 第二次展开(宏参数传递)
MAKE_LABEL2(temp_var, 42)
↓ 最终展开(符号拼接)
temp_var42