在尝试调查代码中的问题时,我是调试打印的粉丝:
cout << "foo:" << foo << "bar:" << bar << "baz:" << baz;
由于我经常编写这样的代码,如果我可以使它更通用并且更容易输入,那将是非常棒的。也许是这样的:
DEBUG_MACRO(foo, bar, baz);
即使foo
,bar
和baz
解析为变量名,而不是字符串,是否可以使用其变量名来创建字符串"foo:"
,{ {1}}和"bar:"
?你能编写一个带有未指定数量参数的函数或宏吗?
答案 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;
答案 2 :(得分:0)
你能编写一个带有未指定数量的函数吗? 参数Δ
是的,但通常你不应该。
您可以使用声明中的elipses声明一个带有未指定数量参数的函数:
int foo(string foo, ...)
但这有很大的问题。最大的问题是它打破了类型安全。考虑当您使用另一个具有未指定参数列表错误
的函数时会发生什么:int n = 42;
char buf[256] = {};
sprintf(buf, "%s", n);
这是一个错误 - 我已经指定了一个字符串,但是传递了int
。最好的情况是,这将在我第一次调试程序时立即执行并执行爆炸。然而,更有可能的是,代码永远不会运行,直到生产中出现异常情况,然后它将在交易日的中间降低整个程序。客户会打电话给你大喊大叫,取消单位等等......好吧,我是戏剧性的,但重要的是类型安全是你的朋友,即使你有一种爱恨交织的关系它