在Qt/GCC/C++;如何创建一个包装器,它既捕获参数表达式文本,又 returns/casts 参数的显式类型?
In Qt/GCC/C++; How to create a wrapper which both captures an argument expression text, and returns/casts the argument's explicit type?
背景故事(可以跳过)
在尽我所能地形成问题时,我被告知 #define
宏的第二组括号不是我认为的 return
,但实际上是cast
。对此,据我所知;捕获表达式文本的唯一方法是使用 #define
宏。棘手的部分,也许是不可能的,是捕获显式 type
的文本,但我知道什么?
还有;我将其指定给 Qt 而不仅仅是 C++/gcc 的原因是,我认为解决方案可能涉及 class 之类的 QVariant
,它添加了一些多态性,但这并不理想,因为它很难区分一些不同的基本类型,比如 int
和 bool
.
我希望达到的目标
基本上,我想要一个包装器,我猜是一个宏,它将记录嵌套表达式文本、它的值和return它的确切嵌套类型(没有隐式转换)。
例如:
/* Basic Definitions */
// log() could be overloaded or use different namespaces if need be
// and have preproccessor directives choose the appropriate one,
// although I dont suspect that is possible.
QVariant log(QString expression, QVariant value, QString type);
// TYPE is placeholder code. Normally I specify a real type like "bool"
// I am hoping TYPE can represent the captured type text
// #EXPR returns the text of the expression, in case you didnt know
#define LOG(EXPR)(TYPE)(log(#EXPR, EXPR, TYPE));
在此示例代码中:
/* Sample Code */
QString path;
if (LOG(path.isEmpty())) {
path = LOG(QDir::currentPath());
}
包装器 LOG
应记录以下内容:
Expression: "path.isEmpty()" Value: "True" Type: "bool"
Expression: "QDir::currentPath()" Value: "/home/akiva/Programming/" Type: "QString"
我想看看我是否可以实现这个 而不必 求助于多个宏名称空间,如下所示:
/* Bad solution because I dont want to have to specify LOG_bool & LOG_QString */
QString path;
if (LOG_bool(path.isEmpty())) {
path = LOG_QString(QDir::currentPath());
}
我想如果我能捕捉到类型的文本,一种可能的解决方案就会自行显现,但我对所有解决方案持开放态度,无论是宏、模板、函数还是您拥有的。
我的最低要求是:
- 需要捕捉表情文字。 (我知道如何使用宏来做到这一点)
- 只需要一个包装命名空间,因为我不想意外使用错误的包装破坏我的日志或可能导致隐式转换,从而可能改变包装表达式的预期行为。
- 包装器必须 return/cast 嵌套表达式的确切类型,或者换句话说,不影响嵌套表达式的确切预期行为。
能够实际记录类型,如 Type: "bool"
和 Type: "QString"
会很好,但不是必需的。
我希望这一切都有意义。谢谢。
基本方法不是使用 QVariant
,而是使用一个模板,该模板 returns 表达式的值,类型相同:
#define LOG(EXPR) (log(#EXPR, EXPR))
void log(const std::string &); // logging function
std::string demangle(const char*); // demangler - see below
template <typename T> T log(const char * expr, T &&value) {
auto const &type = std::typeid(value);
std::ostringstream os;
os << "expression \" << expr << "\" = (" << value << ") type: "
<< demangle(type.name());
log(os.str());
return std::forward(value);
}
demangler 可以改编自 this answer:
#ifdef __GNUG__
#include <cxxabi.h>
#include <memory>
std::string demangle(const char *name) {
int status;
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return {(status==0) ? res.get() : name};
}
#else
std::string demangle(const char *name) {
return {name};
}
#endif
如果你想使用 Qt 类型,你会使用 QString
而不是 std::string
:
void log(const QString &); // logging function
QString demangle(QLatin1String); // demangler - see below
template <typename T> T log(QLatin1String expr, T &&value) {
auto const type = demangle(std::typeid(value).name());
log(QStringLiteral("expression \"%1\" = (%2) type: %3")
.arg(expr).arg(value).arg(type));
return std::forward(value);
}
#ifdef __GNUG__
#include <cxxabi.h>
#include <memory>
QString demangle(QLatin1String name) {
int status;
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name.latin1(), NULL, NULL, &status),
std::free
};
return {(status==0) ? QLatin1String(res.get()) : name};
}
#else
QString demangle(QLatin1String name) { return {name}; }
#endif
背景故事(可以跳过)
在尽我所能地形成问题时,我被告知 #define
宏的第二组括号不是我认为的 return
,但实际上是cast
。对此,据我所知;捕获表达式文本的唯一方法是使用 #define
宏。棘手的部分,也许是不可能的,是捕获显式 type
的文本,但我知道什么?
还有;我将其指定给 Qt 而不仅仅是 C++/gcc 的原因是,我认为解决方案可能涉及 class 之类的 QVariant
,它添加了一些多态性,但这并不理想,因为它很难区分一些不同的基本类型,比如 int
和 bool
.
我希望达到的目标
基本上,我想要一个包装器,我猜是一个宏,它将记录嵌套表达式文本、它的值和return它的确切嵌套类型(没有隐式转换)。
例如:
/* Basic Definitions */
// log() could be overloaded or use different namespaces if need be
// and have preproccessor directives choose the appropriate one,
// although I dont suspect that is possible.
QVariant log(QString expression, QVariant value, QString type);
// TYPE is placeholder code. Normally I specify a real type like "bool"
// I am hoping TYPE can represent the captured type text
// #EXPR returns the text of the expression, in case you didnt know
#define LOG(EXPR)(TYPE)(log(#EXPR, EXPR, TYPE));
在此示例代码中:
/* Sample Code */
QString path;
if (LOG(path.isEmpty())) {
path = LOG(QDir::currentPath());
}
包装器 LOG
应记录以下内容:
Expression: "path.isEmpty()" Value: "True" Type: "bool"
Expression: "QDir::currentPath()" Value: "/home/akiva/Programming/" Type: "QString"
我想看看我是否可以实现这个 而不必 求助于多个宏名称空间,如下所示:
/* Bad solution because I dont want to have to specify LOG_bool & LOG_QString */
QString path;
if (LOG_bool(path.isEmpty())) {
path = LOG_QString(QDir::currentPath());
}
我想如果我能捕捉到类型的文本,一种可能的解决方案就会自行显现,但我对所有解决方案持开放态度,无论是宏、模板、函数还是您拥有的。
我的最低要求是:
- 需要捕捉表情文字。 (我知道如何使用宏来做到这一点)
- 只需要一个包装命名空间,因为我不想意外使用错误的包装破坏我的日志或可能导致隐式转换,从而可能改变包装表达式的预期行为。
- 包装器必须 return/cast 嵌套表达式的确切类型,或者换句话说,不影响嵌套表达式的确切预期行为。
能够实际记录类型,如 Type: "bool"
和 Type: "QString"
会很好,但不是必需的。
我希望这一切都有意义。谢谢。
基本方法不是使用 QVariant
,而是使用一个模板,该模板 returns 表达式的值,类型相同:
#define LOG(EXPR) (log(#EXPR, EXPR))
void log(const std::string &); // logging function
std::string demangle(const char*); // demangler - see below
template <typename T> T log(const char * expr, T &&value) {
auto const &type = std::typeid(value);
std::ostringstream os;
os << "expression \" << expr << "\" = (" << value << ") type: "
<< demangle(type.name());
log(os.str());
return std::forward(value);
}
demangler 可以改编自 this answer:
#ifdef __GNUG__
#include <cxxabi.h>
#include <memory>
std::string demangle(const char *name) {
int status;
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return {(status==0) ? res.get() : name};
}
#else
std::string demangle(const char *name) {
return {name};
}
#endif
如果你想使用 Qt 类型,你会使用 QString
而不是 std::string
:
void log(const QString &); // logging function
QString demangle(QLatin1String); // demangler - see below
template <typename T> T log(QLatin1String expr, T &&value) {
auto const type = demangle(std::typeid(value).name());
log(QStringLiteral("expression \"%1\" = (%2) type: %3")
.arg(expr).arg(value).arg(type));
return std::forward(value);
}
#ifdef __GNUG__
#include <cxxabi.h>
#include <memory>
QString demangle(QLatin1String name) {
int status;
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name.latin1(), NULL, NULL, &status),
std::free
};
return {(status==0) ? QLatin1String(res.get()) : name};
}
#else
QString demangle(QLatin1String name) { return {name}; }
#endif