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

Posted

技术标签:

【中文标题】QVariant 中的自定义类型转换为空字符串【英文标题】:Custom type in QVariant converts to empty string 【发布时间】:2014-06-01 21:00:23 【问题描述】:

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

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

测试.h:

struct Test

    QString value_;

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

Q_DECLARE_METATYPE(Test)

令牌.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("");

扫描仪输出示例:

"Token(TT_TEST, )" 
"Token(TT_PLUS, +)" 
"Token(TT_NUMBER, 5)" 
"Token(TT_end, #)" 

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

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();

我必须为我所有的自定义类型都这样做,这感觉非常笨拙和错误。

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

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

?

【问题讨论】:

你在哪里打电话给qRegisterMetatype 我没有,因为文档states:“要在 QVariant 中使用类型 T,使用 Q_DECLARE_METATYPE() 就足够了。要在排队的信号和插槽连接中使用类型 T,qRegisterMetaType()。” and:“警告:此函数仅用于为所有其他用例注册别名 (typedef),而应使用 Q_DECLARE_METATYPE 和 qMetaTypeId()。”目前我还没有实现 UI(还没有!)。 【参考方案1】:

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;

这当然也可以使用Q_DECLARE_METATYPE( MyType ) 并直接在 QVariant 中聚合一个 Token 实例而不是指向 Token 的指针。

另见this post from the Qt forum

【讨论】:

当我回到这个话题时我会尝试一下,这可能是一个更长的时间段,我目前没有使用 Qt:/【参考方案2】:

你需要为自定义类型Token注册一个QString转换器到元对象系统

要做到这一点,您有两种方法:

    您的自定义类型 Token 已经有一个方法 toString()(或等效方法)

那你可以直接把这个方法注册为转换器

#include <QDebug>
#include <QMetaType>
#include <functional>

struct Token

  QString toString() const
  
    return _value;
  

  QString _value;
;

Q_DECLARE_METATYPE( Token )

int main(int argc, char* argv[])

   qRegisterMetaType<Token>();

   QMetaType::registerConverter(&Token::toString);

   Token t "hello";

   QVariant value;
   value.setValue( t );
   qDebug() << value.toString();

    toString() 函数是外部的(不是自定义类型 Token 的方法)

然后你可以使用一元函数注册这个外部toString函数

#include <QDebug>
#include <QMetaType>
#include <functional>

struct Token

 QString _value;
;

Q_DECLARE_METATYPE( Token )

QString tokenToString(const Token &t)

 return t._value;


struct toQString : public std::unary_function<Token,QString>

 QString operator() (const Token &value) const
 
   return tokenToString(value);
 
;


int main(int argc, char* argv[])

  qRegisterMetaType<Token>();
  QMetaType::registerConverter<Token, QString, toQString>(toQString());

  Token t "hello";

  QVariant value;
  value.setValue( t );
  qDebug() << value.toString();

PS:如果你想做的话

qDebug() << value;

您需要在自定义类型中实现 QDebug 运算符, 并将自定义类型Token的这个操作符注册到元对象系统中。

QMetaType::registerDebugStreamOperator<Token>()

【讨论】:

以上是关于QVariant 中的自定义类型转换为空字符串的主要内容,如果未能解决你的问题,请参考以下文章

为 QVariant 指定非自定义类型转换器

将字符串数组转换为WHERE子句中的自定义枚举类型

将函数返回从“std::vector<QString>”转换为“QVariant”

如何在 Qt 中将 QVariant 转换为 QString,反之亦然?

qstring变量怎样转换为qvariant

Scss中的自定义函数