如何用不同数量的信息参数编写一个c ++ assert宏? [英] How to write a c++ assert macro with a varying number of informational arguments?

查看:171
本文介绍了如何用不同数量的信息参数编写一个c ++ assert宏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想写一个类似于标准 assert 的宏 dbgassert 。除了 assert ,我想要 dbgassert 打印任意数量的附加参数(包含调试信息)。

I am trying to write a macro dbgassert similar to the standard assert. In addition to what assert does, I want to dbgassert print an arbitrary number of additional parameters (containing debugging information).

我到目前为止所列的是从此SO回答。但我有我的问题在我的代码与可变参数模板或宏。如果我使用至少一个附加参数(OK行),则 dbgassert 按预期工作。但是如果我没有额外的参数,那么编译失败(问题行)。

What I have so far is listed below, which is adapted from this SO answer. But I am having issue in my code with either variadic templates or macros. If I use at least one additional argument (the OK line), then dbgassert works as expected. But if I give no additional argument, then compilation fails (the problem line).

我有一些变化模板编程的经验(如打印元组)我以前没有使用过可变宏。

I have some experience with variadic template programming (like how to print a tuple), but I haven't used variadic macros before.

有些人可以解释写这个可变参数宏组合的正确方法是什么?

Can some please explain what's the proper way of writing this variadic parameters macro combination?

顺便说一句,有人可以解释宏中的 #EX 魔法吗?它显示的表达式和工作对我在gcc4.8.1。是否受到普遍支持?

By the way, could someone explain the #EX magic in the macro? It shows the expression and works for me on gcc4.8.1. Is it universally supported?

感谢,

//corrected reserved identifier issue and assumption issues per comments
#include <cassert>
#include <iostream>
using namespace std;

template <typename ...Args>
void realdbgassert(const char *msg, const char *file, int line, Args ... args) {
  cout << "Assertion failed! \nFile " << file << ", Line " << line << endl 
       << "  Expression: " << msg << endl;
  std::abort();
}

#define dbgassert(EX,...) \
  (void)((EX) || (realdbgassert (#EX, __FILE__, __LINE__, __VA_ARGS__),0))

int main() {
  dbgassert(1>2,"right","yes"); //OK
  dbgassert(1>2,"right"); //OK.
  //dbgassert(1>2); //Problem. compile error: expected primary-expression before ')' token
                  //#define dbgassert(EX,...) (void)((EX) || (realdbgassert (#EX, __FILE__, __LINE__, __VA_ARGS__)^,0))
}







Original version of the code.

#include <cassert>
#include <sstream>
using namespace std;

#ifdef __cplusplus
extern "C" {
#endif
extern void __assert (const char *msg, const char *file, int line);
#ifdef __cplusplus
};
#endif

template <typename ...Args>
void _realdbgassert(const char *msg, const char *file, int line, Args ... args) {
    stringstream os;
    //... do something
    __assert(msg,file,line);
}
#define dbgassert(EX,...) (void)((EX) || (_realdbgassert (#EX, __FILE__, __LINE__, __VA_ARGS__),0))

int main() {
  dbgassert(1==0,"right"); //Problem line: undefined reference to `__assert'
} 


推荐答案

您的问题是 __ VA_ARGS __ 的值,在问题情况下为空。因此,当预处理器扩展 realdbgassert(#EX,__FILE__,__LINE__,__VA_ARGS __)时,结果是未完成的参数列表 realdbgassert(1> 2 ,foo.c,42,)。请注意,由于 __ VA_ARGS __ 的空展开,参数列表未正确终止。

Your problem is the value of __VA_ARGS__ which is empty in the problem case. So, when the preprocessor expands realdbgassert(#EX, __FILE__, __LINE__, __VA_ARGS__), the result is an unfinished parameter list realdbgassert("1>2", "foo.c", 42, ). Note that the parameter list is not correctly terminated due to the empty expansion of __VA_ARGS__.

需要使用某种伎俩。最好的解决方案是,调整环境,使 __ VA_ARGS __ 包括最后一个无条件参数,并在函数调用结束时与可选的参数一起传递。这是最好的,因为它是标准的C。

To fix this, you need to use some kind of trick. The best solution is, to tweak the circumstances so that __VA_ARGS__ includes the last unconditional argument, and pass that together with the optional ones at the end of the function call. This is best, because it's standard C.

我知道的另一个修复是对该语言的gcc扩展:见 gcc文档页面了解更多详细信息,但您可以通过添加一个双 ## __ VA_ARGS __ 前面:

The other fix that I know of, is a gcc extension to the language: See this gcc documentation page for more detailed info, but you can fix your macro by adding a double ## in front of __VA_ARGS__:

#define dbgassert(EX,...) \
  (void)((EX) || (realdbgassert (#EX, __FILE__, __LINE__, ## __VA_ARGS__),0))






Ps:

是预处理器的字符串化操作符:它将宏参数的值转换为字符串文字,i。 e。而不是粘贴 1> 2 它粘贴1> 2


Ps:
The # is the stringification operator of the preprocessor: it turns the value of the macro parameter into a string literal, i. e. instead of pasting 1>2 it pastes "1>2".

这篇关于如何用不同数量的信息参数编写一个c ++ assert宏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆