【问题标题】:Passing variable name as string to function with default parameters将变量名称作为字符串传递给使用默认参数的函数
【发布时间】:2012-04-15 16:53:27
【问题描述】:

假设有一个调试功能,这里简化为:

void DumpString(char* var, char* varname) {
    printf("%s : '%s'\n", varname, var);
}

char str[10]="foobar";
DumpString(str, "str");

> str : foobar

让我们通过删除传递变量两次的不必要的无关要求来简化它,一次在引号中:

#define VARASSTR(v) #v

void DumpString(char* var) {
    printf("%s : '%s'\n", VARASSTR(var), var);
}

char str[10]="foobar";
DumpString(str);

> var : foobar

哎呀!它使用局部变量名称而不是传入的变量名称。让我们尝试一种不同的(不太理想的)方法:

#define DumpStr(v) DumpString(v, #v)

void DumpString(char* var, char* varname) {
    printf("%s : '%s'\n", varname, var);
}

char str[10]="foobar";
DumpStr(str);

> str : foobar

很好用。但是如果函数稍微复杂一点呢:

void DumpString(char* var, char* varname, int optionalvar=0) {
    printf("%s : '%s'\n", varname, var);
    printf("blah: %d", optionalvar);
}

不能重载宏,所以DumpStr不行,我们已经排除了VARASSTR的版本。

如何处理(不使用多个类似但名称不同的函数/宏)?

【问题讨论】:

  • “如何处理(不使用多个类似但名称不同的函数/宏)?”它不能。你不能重载宏。
  • 您应该尝试一些具有反射功能的语言。不,真的。
  • 您可以使用Variadic macro trick 来“模拟”宏的重载。
  • 感谢您链接我的问题。 :-)
  • 你也不能重载函数(或者你为什么要标记这个问题c),那么问题是什么?

标签: c++ stringify variable-names default-parameters


【解决方案1】:

这是非标准的,但可以作为 GNU C 的扩展:

#define DumpStr(v, ...) DumpString(v, #v, ##__VA_ARGS__)

在 GNU C 中,您不能将任何参数传递给可变参数宏,并且“标记粘贴运算符”## 在逗号和空可变参数列表之间应用时不会产生任何结果(因此尾随逗号被抑制)。

在 Visual C++ 中,我认为标记粘贴运算符 ## 是不必要的(并且可能会破坏宏),因为如果尾随逗号出现在空的可变参数列表之前,Visual C++ 会自动取消它。

请注意,唯一造成这种不标准的原因是有时希望传递一个空的参数列表。可变参数宏在 C99 和 C++11 中都是标准化的。


编辑:这是一个不使用非标准功能的示例。您可以看到为什么有些人真的非常希望在标准中解决这类问题:

#define DUMPSTR_1(v) DumpString(v, #v)
#define DUMPSTR_2(v, opt) DumpString(v, #v, opt)
#define DUMPSTR_NARG(...) DUMPSTR_ARG_N(__VA_ARGS__, 4, 3, 2, 1, 0)
#define DUMPSTR_ARG_N(_1, _2, _3, _4, n, ...) n
#define DUMPSTR_NC(f, ...) f(__VA_ARGS__)
#define DUMPSTR_NB(nargs, ...) DUMPSTR_NC(DUMPSTR_ ## nargs, __VA_ARGS__)
#define DUMPSTR_NA(nargs, ...) DUMPSTR_NB(nargs, __VA_ARGS__)
#define DumpStr(...) DUMPSTR_NA(DUMPSTR_NARG(__VA_ARGS__), __VA_ARGS__)

可能有一些更简洁的方法可以做到这一点。但没那么多。


编辑 2:这是另一个不使用非标准功能的示例,由R..提供

#define STRINGIFY_IMPL(s) #s
#define STRINGIFY(s) STRINGIFY_IMPL(s)
#define ARG1_IMPL(a, ...) a
#define ARG1(...) ARG1_IMPL(__VA_ARGS__, 0)
#define DumpStr(...) DumpString(STRINGIFY(ARG1(__VA_ARGS__)), __VA_ARGS__)

请注意,这需要更改 DumpString 的参数顺序,以便字符串化的函数名称是第一个参数。

【讨论】:

  • 没有像这样的非标准黑客有解决这个问题的方法。
  • 特别是,您将整个参数列表包含在... 中,然后使用宏从__VA_ARGS__ 中提取第一个(或任何您想要的索引)参数。
  • @R.. 是的,有。 wow 是不是很可怕。我添加了一种我鼓吹的独立方式。你能推荐一个更好的吗?
  • 我没用过,但如果你愿意的话,我相信 boost 预处理器会为你隐藏一些丑陋的东西。
  • @Jesse 是的,它会以大量笨拙的依赖为代价。在这与不符合标准之间,我将采用单线解决方案。 (假设它适用于您的编译器。)
猜你喜欢
  • 1970-01-01
  • 2020-01-13
  • 1970-01-01
  • 2021-07-27
  • 1970-01-01
  • 2017-07-21
  • 2020-06-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多