当我试图调查代码中的问题时,我是调试打印的粉丝:
cout << "foo:" << foo << "bar:" << bar << "baz:" << baz;
因为我经常写这样的代码,如果我能让它更通用,更容易输入,那就太棒了。可能是这样的:
DEBUG_MACRO(foo, bar, baz);
即使foo
、bar
和baz
解析为变量名,而不是字符串,是否可以使用它们的变量名来创建字符串"foo:"
、"bar:"
和"baz:"
?你能写一个接受未指定数量的参数的函数或宏吗?
发布于 2012-06-05 15:22:58
如果你有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解决方案,但事实证明递归遍历列表比您希望的要复杂得多。
发布于 2012-06-05 15:13:14
#define DEBUG_MACRO(name) std::cout << #name << " = " << name << std::endl;
发布于 2012-06-05 15:17:33
你能写一个接受未指定参数数量的函数吗?
是的,但通常你不应该这样做。
您可以通过在声明中使用省略号来声明一个接受未指定数量的参数的函数:
int foo(string foo, ...)
但这有很大的问题。最大的问题是它破坏了类型安全。考虑一下当您不正确地使用带有未指定参数列表的另一个函数时会发生什么情况
int n = 42;
char buf[256] = {};
sprintf(buf, "%s", n);
这是一个错误--我指定了一个字符串,但传递了一个int
。最好的情况是,这将在我第一次调试我的程序时执行,并立即爆炸。然而,更有可能的是,在生产中第一次出现异常情况之前,代码永远不会运行,然后它会在交易日中途关闭整个程序。客户会打电话给你,对你大喊大叫,取消单元等等。好吧,我是戏剧性的,但重点是类型安全是你的朋友,即使你对它爱恨交加。
https://stackoverflow.com/questions/10899908
复制相似问题