问题
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.
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:
QString Token::toString() const
{
QStringList sl;
sl << "Token(" << ::toString(type_) << ", ";
sl << value_.toString() << ")";
return sl.join("");
}
Example output from scanner:
"Token(TT_TEST, )"
"Token(TT_PLUS, +)"
"Token(TT_NUMBER, 5)"
"Token(TT_end, #)"
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;
}
and a modified toString()
function:
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:
- 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).
?
回答1:
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;
}
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.
See also this post from the Qt forum
来源:https://stackoverflow.com/questions/23984421/custom-type-in-qvariant-converts-to-empty-string