Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
459 views
in Technique[技术] by (71.8m points)

c++ - Custom type in QVariant converts to empty string

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).

?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...