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。(我有一个模板解决方案早些时候,但我遇到了不同的问题,所以我需要一个例子,如果这是建议)。

?

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的指针。

参见Qt论坛的这篇文章

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

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

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

那么你可以直接将这个方法注册为converter

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

    相关内容

    • 没有找到相关文章

    最新更新