如何创建一个使用字符串格式的给定变量文本的宏(或其他工具)?

时间:2012-06-05 15:09:32

标签: c++ macros

在尝试调查代码中的问题时,我是调试打印的粉丝:

cout << "foo:" << foo << "bar:" << bar << "baz:" << baz;

由于我经常编写这样的代码,如果我可以使它更通用并且更容易输入,那将是非常棒的。也许是这样的:

DEBUG_MACRO(foo, bar, baz);

即使foobarbaz解析为变量名,而不是字符串,是否可以使用其变量名来创建字符串"foo:",{ {1}}和"bar:"?你能编写一个带有未指定数量参数的函数或宏吗?

3 个答案:

答案 0 :(得分:4)

如果您使用C ++ 11,您可以使用可变参数模板执行类型安全且相当简洁的操作,例如:

#include <string>
#include <iostream>

template <typename T>
void debug(const T& v) {
  std::cout << v << "\n";
}

template <typename T, typename... Tail>
void debug(const T& v, const Tail& ...args) {
  std::cout << v << " ";
  debug(args...);
}

#define NVP(x) #x":", (x)

int main() {
  int foo=0;
  double bar=0.1;
  std::string f="str";
  debug(NVP(foo),NVP(bar),NVP(f));
}

此处的NVP宏完全是可选的,只有在您想在代码中打印您引用的名称时才需要。

如果你真的想跳过NVP位,你可以使用Boost预处理器库(或自己动手),例如:

#include <string>
#include <iostream>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>

template <typename T>
void debug_impl(const T& v) {
  std::cout << v << "\n";
}

template <typename T, typename... Tail>
void debug_impl(const T& v, const Tail& ...args) {
  std::cout << v << " ";
  debug_impl(args...);
}

#define NVP(x) #x":", (x)
#define MEMBER( r, data, i, elem ) BOOST_PP_COMMA_IF( i ) NVP(elem)

#define debug( members )                                \
  debug_impl(                                           \
  BOOST_PP_SEQ_FOR_EACH_I( MEMBER,, members )           \
  )


int main() {
  int foo=0;
  double bar=0.1;
  std::string f="str";
  debug((foo)(bar)(f));
}

一些略有奇怪的语法的价格。我的例子基于this answer。我试图使用可变参数宏直接解决这个问题作为一个“纯粹的”C ++ 11解决方案,但事实证明,通过列表递归比你希望的更复杂。

答案 1 :(得分:1)

#define DEBUG_MACRO(name) std::cout << #name << " = " << name << std::endl;

示例:http://ideone.com/agw4i

答案 2 :(得分:0)

  

你能编写一个带有未指定数量的函数吗?   参数Δ

是的,但通常你不应该。

您可以使用声明中的elipses声明一个带有未指定数量参数的函数:

int foo(string foo, ...)

但这有很大的问题。最大的问题是它打破了类型安全。考虑当您使用另一个具有未指定参数列表错误

的函数时会发生什么:

int n = 42;
char buf[256] = {};
sprintf(buf, "%s", n);

这是一个错误 - 我已经指定了一个字符串,但是传递了int。最好的情况是,这将在我第一次调试程序时立即执行并执行爆炸。然而,更有可能的是,代码永远不会运行,直到生产中出现异常情况,然后它将在交易日的中间降低整个程序。客户会打电话给你大喊大叫,取消单位等等......好吧,我是戏剧性的,但重要的是类型安全是你的朋友,即使你有一种爱恨交织的关系它