5

我想动态创建一个唯一的变量名。

这是我的代码:

int call(int i)
{
    return i;
}
 
#define XCAT3(a, b, c)    a ## b ## c
 
#define CALL_2(arg, place, line) int XCAT3(cl, place, line) = call(arg);
 
#define CALL_1(arg)    CALL_2(arg, __FUNCTION__, __LINE__)
 
int main(int argc, char* argv[])
{
    CALL_1(1); /* this is line 20 */
    return 0;
}

这在 GCC ( http://ideone.com/p4BKQ ) 中有效,但不幸的是在 Visual Studio 2010 或 2012 中无效。

错误信息是:

test.cpp(20):错误 C2143:语法错误:缺少 ';' 在'function_string'之前

test.cpp(20):错误 C2143:语法错误:缺少 ';' 在“常数”之前

test.cpp(20): 错误 C2106: '=' : 左操作数必须是左值

如何使用 C++ 创建动态唯一变量名?

解决方案:

#define CAT2(a,b) a##b
#define CAT(a,b) CAT2(a,b)
#define UNIQUE_ID CAT(_uid_,__COUNTER__)

int main(int argc, char* argv[])
{
    int UNIQUE_ID = 1;
    int UNIQUE_ID = 2;
    return 0;
}
4

2 回答 2

6

对于唯一标识符,许多实现都提供了__COUNTER__预处理器宏,随着每次使用,它的数量会不断增加。

#define CAT(a,b) CAT2(a,b) // force expand
#define CAT2(a,b) a##b // actually concatenate
#define UNIQUE_ID() CAT(_uid_,__COUNTER__)

auto UNIQUE_ID() = call(1); // may be _uid_0
auto UNIQUE_ID() = call(2); // may be _uid_1
于 2012-10-03T14:59:39.433 回答
2

您需要将令牌粘贴推迟到参数之后,placeline在宏中递归展开CALL_LATER2。你可以通过将##操作移动到一个单独的宏来做到这一点——只要##没有出现在 的主体中CALL_LATER2,它的所有参数都将被预先扫描为宏:

#define XCAT3(a, b, c)    a ## b ## c
#define CALL_LATER2(fun, h, place, line) \
    auto XCAT3(calllater, place, line) = \
        call_later((fun), (h));

但是,这仍然不能满足您的要求,因为它__FUNCTION__会扩展为带有"字符的字符串,而不是可以粘贴到标识符中的内容。相反,您需要以创建的名称为基础,__LINE__并确保最终可以在不同的编译单元中出现重复的事实不是问题(如果它们是某些函数的本地,那应该没问题,或者您可以将它们放在在匿名命名空间中。)

于 2012-10-02T20:29:06.860 回答