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

时间:2014-06-01 21:00:23

标签: c++ qt c++11 types qvariant

我正在编写一个词汇扫描程序,可以从某些输入生成一个令牌流。这些令牌具有类型。由于我使用的是Qt,因此我选择将令牌数据存储为QVariant。这适用于非自定义类型的令牌数据。

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

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

扫描仪的输出示例:

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

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;
}

和修改后的toString()函数:

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

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

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

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

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

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

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

  1. 您的自定义类型令牌已经有一个方法 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();
}
  1. 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>()