QVariant 中的自定义类型转换为空字符串

hoc*_*chl 4 c++ qt types qvariant c++11

我正在编写一个词法扫描器,它从一些输入生成一个标记流。这些令牌有一个type和一个value。由于我使用的是 Qt,因此我选择将令牌数据存储为QVariant. 这对于非自定义类型的令牌数据非常有效。

不幸的是,我有几个自定义类型也存储在令牌中。令牌具有toString()输出令牌描述(用于调试)的函数,但对于具有自定义类型数据的所有令牌,此函数提供一个空字符串。代码是这样的:

测试.h:

struct Test
{
    QString value_;

    Test(const QString& value = "");
    QString toString();
};

Q_DECLARE_METATYPE(Test)
Run Code Online (Sandbox Code Playgroud)

令牌.h:

struct Token
{
    TokenType type_;
    QVariant value_;
...
    virtual QString toString() const;
};
Run Code Online (Sandbox Code Playgroud)

令牌.cpp:

QString Token::toString() const
{
    QStringList sl;
    sl << "Token(" << ::toString(type_) << ", ";
    sl << value_.toString() << ")";
    return sl.join("");
}
Run Code Online (Sandbox Code Playgroud)

扫描仪输出示例:

"Token(TT_TEST, )" 
"Token(TT_PLUS, +)" 
"Token(TT_NUMBER, 5)" 
"Token(TT_end, #)" 
Run Code Online (Sandbox Code Playgroud)

TT_TEST令牌包含一个 Test 类,我希望该变体打印它的值。不幸的是,这不起作用,我尝试了很多不起作用的解决方案。我目前的解决方法是这样的:

template <typename T>
bool writeToStringList(QStringList& sl, QVariant v)
{
    if (!v.canConvert<T>()) return false;
    sl << v.value<T>().toString();
    return true;
}
Run Code Online (Sandbox Code Playgroud)

和修改后的toString()功能:

sl << "Token(";
sl << ::toString(type_) << ", ";
if (!writeToStringList<Test>(sl, value_)) {
    sl << value_.toString();
}
Run Code Online (Sandbox Code Playgroud)

我必须为我所有的自定义类型执行此操作,这感觉非常笨拙和错误。

我认为必须有更好的解决方案来解决这个问题。你们中的任何人都可以:

  • 告诉我如何以QVariant更好的方式解决问题,或者
  • 建议一个完全不同的解决方案,没有QVariant. (我之前有一个模板解决方案,但我在那里遇到了不同的问题,所以如果有建议,我需要一个例子)。

?

Ste*_*anQ 5

Q_DECLARE_METATYPE() 实际上足以在 QVariant 中启用自定义类型的聚合。不过,这不包括隐式类型转换和 QVariant 上下文中的比较等方面。假设 Qt5,为了便于隐式转换为 QString,您可以执行以下操作:

#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;
}
Run Code Online (Sandbox Code Playgroud)

这当然也是可能的(并且可以节省更多)Q_DECLARE_METATYPE( MyType )并直接在 QVariant 中聚合 Token 实例而不是指向 Token 的指针。

另请参阅Qt 论坛上的这篇文章