【问题标题】:How can I construct a locally unique identifier name? [duplicate]如何构造本地唯一标识符名称? [复制]
【发布时间】:2012-09-23 17:52:04
【问题描述】:

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

这是我的代码:

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

【问题讨论】:

标签: c++ visual-studio-2010 visual-c++ uniqueidentifier c-preprocessor


【解决方案1】:

对于唯一标识符,许多实现都提供了__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

【讨论】:

  • +1,很高兴知道,但我真的很想知道我的代码有什么问题:|
  • @Felix:如前所述,__FUNCTION__ 产生一个类似"main" 的字符串文字,而不是可以用作标识符的一部分的东西。实际上,您的代码根本不应该编译,甚至在 GCC 上也不应该。
  • 接受,因为这是我需要的,但是:我在 VS2012 中启动了一个 Visual Studio 2008 默认命令行项目和另一个项目,并且在这两个项目中 COUNTER 都没有扩展。完整来源:#define UNIQUE_ID uid##__COUNTER__ int main(int argc, char* argv[]) { int UNIQUE_ID = 1; int UNIQUE_ID = 2; return 0; } 给出错误error C2374: 'uid__COUNTER__' : redefinition; multiple initialization 你知道为什么吗?
  • @Felix:好问题。试试#define EXPAND(Arg) Arg#define UNIQUE_ID() _uid_ ## EXPAND(__COUNTER__)
  • 这行不通,因为 ## 粘贴操作符按字面意思接受它的参数。但是扩展计数器是一个好主意并且奏效了!现在我只需要正确粘贴它...
【解决方案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__,并确保您最终可以在不同的编译单元中出现重复的事实不是问题(如果它们是某个函数的本地,那应该没问题,或者您可以将它们放在匿名命名空间中。)

【讨论】:

  • 这仍然对我不起作用 - 请查看我更新的问题
猜你喜欢
  • 1970-01-01
  • 2015-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-04
  • 2011-11-19
相关资源
最近更新 更多