问题描述
我正在写一个词法扫描器,它从某些输入生成令牌流.这些令牌具有 type 和 value .由于我使用的是Qt,因此我选择将令牌数据存储为QVariant
.对于非自定义类型的令牌数据,此方法效果很好.
I'm writing a lexical scanner that generates a stream of tokens from some input. Those tokens have a type and a value. Since I'm using Qt I chose to store the token data as a QVariant
. This works pretty well for token data that is of a non-custom type.
不幸的是,我还有几种自定义类型,它们也存储在令牌中.令牌具有toString()
函数,该函数输出令牌描述(用于调试),但是对于所有具有自定义类型数据的令牌,此函数将提供一个空字符串.代码如下:
Unfortunately, I have several custom types that are stored inside of tokens as well. The tokens have a toString()
function that outputs a token description (for debugging), but for all tokens that have data of a custom type this function gives an empty string. The code goes like this:
Test.h:
struct Test
{
QString value_;
Test(const QString& value = "");
QString toString();
};
Q_DECLARE_METATYPE(Test)
Token.h:
struct Token
{
TokenType type_;
QVariant value_;
...
virtual QString toString() const;
};
Token.cpp:
Token.cpp:
QString Token::toString() const
{
QStringList sl;
sl << "Token(" << ::toString(type_) << ", ";
sl << value_.toString() << ")";
return sl.join("");
}
扫描仪输出示例:
"Token(TT_TEST, )"
"Token(TT_PLUS, +)"
"Token(TT_NUMBER, 5)"
"Token(TT_end, #)"
TT_TEST
令牌包含一个Test类,我希望该变体能够打印出它的值.不幸的是,这不起作用,并且我尝试了许多无效的解决方案.我当前的解决方法如下:
The TT_TEST
token contains a Test class and I would expect the variant to print it's value. Unfortunately this does not work, and I've tried a lot of solutions that did not work. My current workaround looks like this:
template <typename T>
bool writeToStringList(QStringList& sl, QVariant v)
{
if (!v.canConvert<T>()) return false;
sl << v.value<T>().toString();
return true;
}
和修改后的toString()
函数:
sl << "Token(";
sl << ::toString(type_) << ", ";
if (!writeToStringList<Test>(sl, value_)) {
sl << value_.toString();
}
我必须对所有自定义类型都这样做,这感觉非常笨拙和错误.
and I have to do this for all my custom types which just feels pretty clumsy and wrong.
我认为必须对此问题有更好的解决方案.你们任何人都可以:
I figure there must be a better solution to this problem. Can anyone of you:
- 告诉我如何更好地解决
QVariant
问题,或者 - 建议不使用
QVariant
的完全不同的解决方案. (我之前有一个模板解决方案,但在那里遇到了不同的问题,因此,如果有建议,我将需要一个示例.)
- Tell me how to solve the problem with the
QVariant
in a better way, or - suggest a totally different solution without a
QVariant
. (I had a template solution earlier but I ran into different problems there, so I would need an example if that is suggested).
?
推荐答案
Q_DECLARE_METATYPE()实际上足以在QVariant中启用自定义类型的聚合.但是,这并不涵盖诸如隐式类型转换和QVariant上下文中的比较之类的方面.假设使用Qt5,以便于隐式转换为QString,您可以执行以下操作:
Q_DECLARE_METATYPE() is in fact sufficient to enable aggregation of a custom type in a QVariant. This does not cover aspects like implicit type conversion and comparison in context of the QVariant though.Qt5 assumed, to facilitate implicit conversion to QString you may do the following:
#include <QMetaType>
struct Token {
QString _value;
};
Q_DECLARE_METATYPE( Token* );
QString tokenToString( Token* t ) {
return t->_value );
}
int main(int argc, char* argv[]) {
QMetaType::registerConverter<Token*,QString>( tokenToString );
Token t = { QString("hello") };
QVariant value;
value.setValue( &t );
std::cout << value << std::endl;
}
使用Q_DECLARE_METATYPE( MyType )
当然也可以(并且更节省),并且可以直接在QVariant中聚集Token实例,而不是指向Token的指针.
This is of course also possible (and more save) with Q_DECLARE_METATYPE( MyType )
and directly aggregating a Token instance in the QVariant instead of a pointer to Token.
另请参见来自Qt论坛的帖子
这篇关于QVariant中的自定义类型转换为空字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!