如何做一个可变的宏和/或模板和/或捕获表达式及其评估的函数?
How to do a variadic macro and or template and or function that captures the expression as well as its evaluation?
我用各种 <<
运算符重载了 class
inline QString operator<<(bool boolean) {
return (boolean ? QString("true") : QString("false"));
}
inline QString operator<<(char const *string) {
return QString(string);
}
inline QString operator<<(int number) {
return QString::number(number);
}
基本上我想做的是编写一个捕获表达式的调试输出,如下所示:
#define DEBUG(...)
DEBUG(QString("foobar"), someObject.toInt());
// Expression 1: """QString("foobar")"""
// Expression 2: """someObject.toInt()"""
并结合其评价:
#define DEBUG(...)
DEBUG(QString("foobar"), someObject.toInt());
// Evaluation 1: "foobar"
// Evaluation 2: "1234"
所有前缀为
__FILE__;
QString::number(__LINE__);
__PRETTY_FUNCTION__;
它应该输出如下内容:
#define DEBUG(...)
DEBUG(QString("foobar"), someObject.toInt());
///////////////// Output /////////////////
File: /home/akiva/Programming/MyApp/source.cpp
Line: 123
Func: void doSomething();
QString("foobar")
"foobar"
someObject.toInt()
"1234"
我在执行此操作时遇到了问题,因为执行递归可变参数宏并不完全合法。我还有一些额外的困难,因为据我所知,我以前使用可变参数模板和 std::forward
的方法在 Web Assembly 中不起作用。理想情况下,经过测试的解决方案也将与 Wasm 兼容。
谢谢。
我通过构建一个小型解析器来解析初始表达式来解决这个问题。解析器肯定有错误,因为我只是将它拼凑了一个多小时。
里面一个class:
static void _Continue(QStringList &sl)
{
QString s;
{
s.append(sl.takeFirst()); // File
s.append(":");
s.append(sl.takeFirst()); // Line
s.append("<br> "); // Outputting to a text box.
s.append(sl.takeFirst()); // Func
}
/* Parse Expression */
QStringList args;
{
QString expr(sl.takeFirst()); // Expression
bool isQuote (false); // ""
bool isLiteral(false); // ''
bool isPointer(false); // ->
int roundLevel(0); // ()
int curlyLevel(0); // {}
int squarLevel(0); // []
int angleLevel(0); // < > // Fixme handle <<, >>, <= etc
expr.remove(QRegularExpression("[/][*].*[*][/]")); // Remove Comments
QString arg;
QRegularExpression re_CommaWhitespaceAtBeginning("^[, \t\n]*");
while (!expr.isEmpty()) {
if (isPointer && expr.front().unicode() != u'>') { isPointer = false; }
switch (expr.front().unicode()) {
case u'-' : {
isPointer = true; // potentially
break;
}
case u'"' : {
isQuote = !isQuote;
break;
}
case u'\'': {
isLiteral = !isLiteral;
break;
}
case u'(' : {
if (isQuote) { break; }
roundLevel++;
break;
}
case u')' : {
if (isQuote) { break; }
roundLevel--;
break;
}
case u'[' : {
if (isQuote) { break; }
squarLevel++;
break;
}
case u']' : {
if (isQuote) { break; }
squarLevel--;
break;
}
case u'{' : {
if (isQuote) { break; }
curlyLevel++;
break;
}
case u'}' : {
if (isQuote) { break; }
curlyLevel--;
break;
}
case u'<' : {
if (isQuote) { break; }
angleLevel++;
break;
}
case u'>' : {
if (isQuote || isPointer) {
isPointer = false;
break;
}
angleLevel--;
break;
}
case u'\': {
if (isQuote) { arg.append(expr.front()); }
break;
}
case u',' : {
if (isQuote
|| isLiteral
|| roundLevel
|| curlyLevel
|| squarLevel
|| angleLevel) { break; }
args << arg.remove(re_CommaWhitespaceAtBeginning);
arg.clear();
break;
}
default : {
}
}
arg.append(expr.front());
expr.remove(0,1);
}
args << arg.remove(re_CommaWhitespaceAtBeginning);
}
// sl should now have only values;
// args should be shorter than sl, even with error
for (int i = 0; !args.isEmpty(); i++) {
sl.replace(i, args.takeFirst() + "<br/>" + sl.at(i));
}
sl.prepend(s);
/* Messages stored on a map, signal sent to update it. */
MainWindow::s_StdoutMap.append(sl.join("<br/><br/>"));
emit MainWindow::s_MW->on_actionUpdate_triggered();
}
template<typename type, typename ... T>
static void _Continue(QStringList &sl, type t, T ... args)
{
sl << (*MainWindow::s_MW << t); // overloaded << operator to handle T
MainWindow::_Continue(sl, args ...);
}
template<typename ... T>
static void _Start(QString file, int line, QString func, QString expr, T ... args)
{
QStringList sl;
{
sl << file;
sl << QString::number(line);
sl << func;
sl << expr;
}
MainWindow::_Continue(sl, args ...);
}
#define ct_Debug(...)MainWindow::_Start(__FILE__, __LINE__, __PRETTY_FUNCTION__,\
#__VA_ARGS__, __VA_ARGS__)
它给了我这样的输出:
如果你想知道为什么它不在控制台中,如前所述,这是用于 web assembly 的。
我用各种 <<
运算符重载了 class
inline QString operator<<(bool boolean) {
return (boolean ? QString("true") : QString("false"));
}
inline QString operator<<(char const *string) {
return QString(string);
}
inline QString operator<<(int number) {
return QString::number(number);
}
基本上我想做的是编写一个捕获表达式的调试输出,如下所示:
#define DEBUG(...)
DEBUG(QString("foobar"), someObject.toInt());
// Expression 1: """QString("foobar")"""
// Expression 2: """someObject.toInt()"""
并结合其评价:
#define DEBUG(...)
DEBUG(QString("foobar"), someObject.toInt());
// Evaluation 1: "foobar"
// Evaluation 2: "1234"
所有前缀为
__FILE__;
QString::number(__LINE__);
__PRETTY_FUNCTION__;
它应该输出如下内容:
#define DEBUG(...)
DEBUG(QString("foobar"), someObject.toInt());
///////////////// Output /////////////////
File: /home/akiva/Programming/MyApp/source.cpp
Line: 123
Func: void doSomething();
QString("foobar")
"foobar"
someObject.toInt()
"1234"
我在执行此操作时遇到了问题,因为执行递归可变参数宏并不完全合法。我还有一些额外的困难,因为据我所知,我以前使用可变参数模板和 std::forward
的方法在 Web Assembly 中不起作用。理想情况下,经过测试的解决方案也将与 Wasm 兼容。
谢谢。
我通过构建一个小型解析器来解析初始表达式来解决这个问题。解析器肯定有错误,因为我只是将它拼凑了一个多小时。
里面一个class:
static void _Continue(QStringList &sl)
{
QString s;
{
s.append(sl.takeFirst()); // File
s.append(":");
s.append(sl.takeFirst()); // Line
s.append("<br> "); // Outputting to a text box.
s.append(sl.takeFirst()); // Func
}
/* Parse Expression */
QStringList args;
{
QString expr(sl.takeFirst()); // Expression
bool isQuote (false); // ""
bool isLiteral(false); // ''
bool isPointer(false); // ->
int roundLevel(0); // ()
int curlyLevel(0); // {}
int squarLevel(0); // []
int angleLevel(0); // < > // Fixme handle <<, >>, <= etc
expr.remove(QRegularExpression("[/][*].*[*][/]")); // Remove Comments
QString arg;
QRegularExpression re_CommaWhitespaceAtBeginning("^[, \t\n]*");
while (!expr.isEmpty()) {
if (isPointer && expr.front().unicode() != u'>') { isPointer = false; }
switch (expr.front().unicode()) {
case u'-' : {
isPointer = true; // potentially
break;
}
case u'"' : {
isQuote = !isQuote;
break;
}
case u'\'': {
isLiteral = !isLiteral;
break;
}
case u'(' : {
if (isQuote) { break; }
roundLevel++;
break;
}
case u')' : {
if (isQuote) { break; }
roundLevel--;
break;
}
case u'[' : {
if (isQuote) { break; }
squarLevel++;
break;
}
case u']' : {
if (isQuote) { break; }
squarLevel--;
break;
}
case u'{' : {
if (isQuote) { break; }
curlyLevel++;
break;
}
case u'}' : {
if (isQuote) { break; }
curlyLevel--;
break;
}
case u'<' : {
if (isQuote) { break; }
angleLevel++;
break;
}
case u'>' : {
if (isQuote || isPointer) {
isPointer = false;
break;
}
angleLevel--;
break;
}
case u'\': {
if (isQuote) { arg.append(expr.front()); }
break;
}
case u',' : {
if (isQuote
|| isLiteral
|| roundLevel
|| curlyLevel
|| squarLevel
|| angleLevel) { break; }
args << arg.remove(re_CommaWhitespaceAtBeginning);
arg.clear();
break;
}
default : {
}
}
arg.append(expr.front());
expr.remove(0,1);
}
args << arg.remove(re_CommaWhitespaceAtBeginning);
}
// sl should now have only values;
// args should be shorter than sl, even with error
for (int i = 0; !args.isEmpty(); i++) {
sl.replace(i, args.takeFirst() + "<br/>" + sl.at(i));
}
sl.prepend(s);
/* Messages stored on a map, signal sent to update it. */
MainWindow::s_StdoutMap.append(sl.join("<br/><br/>"));
emit MainWindow::s_MW->on_actionUpdate_triggered();
}
template<typename type, typename ... T>
static void _Continue(QStringList &sl, type t, T ... args)
{
sl << (*MainWindow::s_MW << t); // overloaded << operator to handle T
MainWindow::_Continue(sl, args ...);
}
template<typename ... T>
static void _Start(QString file, int line, QString func, QString expr, T ... args)
{
QStringList sl;
{
sl << file;
sl << QString::number(line);
sl << func;
sl << expr;
}
MainWindow::_Continue(sl, args ...);
}
#define ct_Debug(...)MainWindow::_Start(__FILE__, __LINE__, __PRETTY_FUNCTION__,\
#__VA_ARGS__, __VA_ARGS__)
它给了我这样的输出: