Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何编写c++;使用不同数量的信息参数断言宏?_C++_C++11_Assert_Variadic Templates_Variadic Macros - Fatal编程技术网

C++ 如何编写c++;使用不同数量的信息参数断言宏?

C++ 如何编写c++;使用不同数量的信息参数断言宏?,c++,c++11,assert,variadic-templates,variadic-macros,C++,C++11,Assert,Variadic Templates,Variadic Macros,我正在尝试编写一个宏dbgasert,类似于标准的assert。除了assert所做的之外,我还想dbgassert打印任意数量的附加参数(包含调试信息) 到目前为止,我已经在下面列出了,这是改编自。但我的代码中存在变量模板或宏的问题。如果我至少使用了一个附加参数(OK行),那么dbgassert将按预期工作。但如果我没有给出额外的参数,编译就会失败(问题行) 我有一些可变模板编程的经验(比如如何打印元组),但我以前从未使用过可变宏 请解释一下写这个可变参数宏组合的正确方法是什么 顺便问一下,有

我正在尝试编写一个宏
dbgasert
,类似于标准的
assert
。除了
assert
所做的之外,我还想
dbgassert
打印任意数量的附加参数(包含调试信息)

到目前为止,我已经在下面列出了,这是改编自。但我的代码中存在变量模板或宏的问题。如果我至少使用了一个附加参数(OK行),那么
dbgassert
将按预期工作。但如果我没有给出额外的参数,编译就会失败(问题行)

我有一些可变模板编程的经验(比如如何打印元组),但我以前从未使用过可变宏

请解释一下写这个可变参数宏组合的正确方法是什么

顺便问一下,有人能解释一下宏中的
#EX
魔力吗?它显示了表达式并在gcc4.8.1上对我有效。它是否得到普遍支持

谢谢


代码:

//更正了每个注释的保留标识符问题和假设问题
#包括
#包括
使用名称空间std;
模板
void realdbgassert(常量字符*msg,常量字符*file,int行,Args…Args){

不能你必须写函数的内容
\u assert
-如果你指定它是
extern
,你应该将包含函数定义的文件附加到编译过程中。如果你不知道如何编写多文件程序,我真的帮不了你。

你假设
assert
是im通过调用
\uu assert
来实现。这很可能是一个特定实现的工作方式,但在一般情况下肯定不能依赖


相反,请执行以下操作:测试您的条件并在出现故障时将诊断信息发送到标准错误,然后调用
std::abort
您的问题是
\uuu VA\u ARGS\uuuuu>的值,该值在问题情况下为空。因此,当预处理器展开
realdbgassert(#EX,uu文件,u行,u VA\u ARGS_uuu)
,结果是一个未完成的参数列表
realdbgassert(“1>2”,“foo.c”,42,)
。请注意,由于
\uu VA\u ARGS\uuuuuu>的空扩展,参数列表未正确终止

要解决这个问题,您需要使用某种技巧。最好的解决方案是,调整环境,使
\uu VA\u ARGS\uuu
包含最后一个无条件参数,并在函数调用结束时将其与可选参数一起传递。这是最好的,因为它是标准C

我知道的另一个修复是对该语言的gcc扩展:有关更多详细信息,请参见gcc文档页,但您可以通过在
\uu VA_ARGS\uuu
前面添加一个双精度
\u35;
来修复宏:

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

附言:

#
是预处理器的字符串化操作符:它将宏参数的值转换为字符串文字,即粘贴
“1>2”
而不是粘贴
<1>2”
放置标记粘贴操作符(##)在
\uuuu VA\u ARGS\uuuu
之前。如果
\uuu VA\u ARGS\uuu
为空,则删除
\uuuu VA\u ARGS\uuuu
之前的逗号

您的宏将是:

#define dbgassert(EX,...) \
  (void)((EX) || (realdbgassert (#EX, __FILE__, __LINE__, ##__VA_ARGS__),0))
请注意,令牌粘贴是GNU CPP扩展,正如正确提到的其他海报之一(请参阅)


MS编译器(在VS2010下测试)不需要标记粘贴,如果
\uuu VA\u ARGS\uuu
为空,它只需删除尾随逗号。请参见:

作为说明,除了@cmaster和@ds27680的解决方案外,我还找到了另一种解决尾随逗号问题的方法。由于使用
\uu VA\u ARGS\uu
会导致额外的逗号,我可以打包
\uu VA\u ARGS__
转换为
std::tuple
或函数调用,并使用tuple/result作为实函数的参数。现在空
\uuuu VA\u ARGS\uu
不会有问题,因为它被压缩为一个有效值(即空元组或空函数的返回值)。我想这在代码中比较长,但在不涉及
##
的情况下更便于移植

上述两种情况分别显示在下面代码中的
dbgassert
dbgassert1
宏中

#include <cassert>
#include <iostream>
#include <tuple>
using namespace std;

template <typename ...Args>
string print_tuple(tuple<Args...> tp) {
  return ""; //print the tuple...
}

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

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

void realdbgassert1(string info,const char *msg, const char *file, int line) {
  cout << "Assertion failed! \nFile " << file << ", Line " << line << endl 
       << "  Expression: " << msg << endl
       << "  Info: " << info << endl;
  std::abort();
}

template <typename ...Args>
string print_info(Args ... args) {
  return "";  //print stuff
}

#define dbgassert1(EX,...) \
  (void)((EX) || (realdbgassert1 (print_info(__VA_ARGS__),#EX,__FILE__, __LINE__),0))


int main() {
  dbgassert(1>2,"right","yes"); //OK
  dbgassert(1>2,"right"); //OK
  dbgassert(1>2); //OK now
  dbgassert1(1>2); //OK too
}
#包括
#包括
#包括
使用名称空间std;
模板
字符串打印元组(元组tp){
返回“”;//打印元组。。。
}
模板
void realdbgassert(元组信息,常量字符*消息,常量字符*文件,int行){

您是否正在使用。无论如何,什么是
\u assert
?当然不是标准函数。或者您只是试图使用您的实现没有的实现细节?
../ccZ47ZOL.o:test7.cpp:.text$\u Z14\u realdbgassertipkceevs1\u S1\u iDpT\uz14\u realdbgassertipkceevs1\u iDpT]+0x65):未定义的对
@断言的引用。嗯,你期望得到什么?你还没有提供
\uu断言
的定义。或者你是说你的标准库实现提供了这样一个函数?我想
\uu断言
断言
函数背后的函数。我在这里看到了它:我想是看台ard assert不能是实函数,而且在
assert
宏后面必须有实函数,对吗?因为
assert
报告问题行,如果
assert
是实函数,它会报告
中的行号。没有标准处理程序(即实assert函数)吗在标准中?谢谢。但是我对变量宏还有其他问题。请看更新。@TingL看到我在手边努力写一个答案,结果发现你比我快。很好的解释。你得到了我的支持。我已经在考虑将无条件参数包装到一个对象中,以便它们可以隐式传递这样的变量成员函数
包装器
#define dbgassert(EX,...) \
  (void)((EX) || (realdbgassert (#EX, __FILE__, __LINE__, ##__VA_ARGS__),0))
#include <cassert>
#include <iostream>
#include <tuple>
using namespace std;

template <typename ...Args>
string print_tuple(tuple<Args...> tp) {
  return ""; //print the tuple...
}

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

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

void realdbgassert1(string info,const char *msg, const char *file, int line) {
  cout << "Assertion failed! \nFile " << file << ", Line " << line << endl 
       << "  Expression: " << msg << endl
       << "  Info: " << info << endl;
  std::abort();
}

template <typename ...Args>
string print_info(Args ... args) {
  return "";  //print stuff
}

#define dbgassert1(EX,...) \
  (void)((EX) || (realdbgassert1 (print_info(__VA_ARGS__),#EX,__FILE__, __LINE__),0))


int main() {
  dbgassert(1>2,"right","yes"); //OK
  dbgassert(1>2,"right"); //OK
  dbgassert(1>2); //OK now
  dbgassert1(1>2); //OK too
}