1

I'm having a hard time of converting std::string to QVariant and QVariant back to std::string. In both cases I end up with empty value (default QVariant, just like it was initialized with no parameters) and empty std::string ("").

These are relevant parts of my code:

bool TestItemListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    // processing of other function arguments, checks, etc.
    (*myData)[row].setName(value.value<std::string>());
    // here I end up with ""
}

QVariant TestItemListModel::data(const QModelIndex &index, int role) const
{
    // again all the checks, etc.
    return QVariant::fromValue<std::string>((*myData)[row].getName());
}

I found a question similar to this one and this is how it was meant to work. I also did additional thing the answer mentioned, so in my main.cpp I have this:

qRegisterMetaType<std::string>("std::string");

and in my testitemlistmodel.h I have this (before class declaration):

Q_DECLARE_METATYPE(std::string)

I use Qt5.8.

EDIT

I found the source for this type of conversion: http://www.qtcentre.org/threads/45922-best-way-to-extend-QVariant-to-support-std-string?p=208049#post208049. Now I just realized it's quite old and may not work anymore. If that's the case, what would be the best way of doing that?

Community
  • 1
  • 1
pzaj
  • 1,062
  • 1
  • 17
  • 37
  • Why not just convert it to a QString and let Qt take care of it for you? – MrEricSir Jun 25 '17 at 20:42
  • Isn't there a significant overhead? – pzaj Jun 25 '17 at 20:45
  • 1
    That's a very complicated question, and only your profiler can tell you for certain. The main issues are how many strings we're talking about, how long they are, and what encoding you're using in your `std::string` (which is typically platform dependent.) – MrEricSir Jun 25 '17 at 21:04
  • I see, well. I have custom model `ItemsModel` deriving from `QAbstractListModel` backed by `std::vector`, where `T` contains few `std::string` members. the conversion is done in `ItemsModel::data(...)` [`std::string -> QVariant`], but what happens to them I don't know. `QVariant -> std::string` is done in `ItemsModel::setData(...)` and `QVariant` here is passed by const reference. Unfortunately, I don't know how it works internally, so I can't say anything more about how it's being used by `QListView` instance bound to this model. – pzaj Jun 25 '17 at 21:15
  • 1
    Can you provide a [mcve]? As in, convert a std string to a qvariant and back in a somple test function and demonstrate the value not being there? As it stands, you have a complex app where you have shown a few lines of code that may or may not contain your problem, using pointers with unknown types and a myriad of unknown unknowns. – Yakk - Adam Nevraumont Jun 26 '17 at 00:02
  • @Yakk I was about to do this, but once I compiled and run this example, it simply worked (I took the one from link I posted). While I understand that pointers and other unknowns could be the problem here, the other solutions listed (using `QSstring` or `QByteArray` as a median type) work as expected. My guess is that it has something to do with either the `qRegisterMetaType` or the `Q_DECLARE_METATYPE` macro. I decided to use QByteArray instead, which seems to work just fine and offer reliability I can't reproduce with my solution posted here. – pzaj Jun 26 '17 at 09:07

1 Answers1

3

How about using the QString as a median type? It's a little overhead but much easier to maintain the code:

/* std::string to QVariant */ {
    std::string source { "Hello, World!" };
    QVariant destination;        

    destination = QString::fromStdString(source);
    qDebug() << destination;
}

/* QVariant to std::string */ {
    QVariant source { "Hello, World!" };
    std::string destination;

    destination = source.toString().toStdString();
    qDebug() << destination.c_str();
}

The QVariant has a constructor for QString which can be built from std::string and a QVariant object can be converted to QString which can be coverted to std::string.


Another option is using QByteArray instead of QString which just copies your std::string character-by-character and doesn't converts it to Unicode like QString does:

// std::string to QVariant
myQVariant.setValue<QByteArray>(myStdString.c_str());

// std::string to QVariant
myStdString = myQVariant.value<QByteArray>().constData();
Akira
  • 4,385
  • 3
  • 24
  • 46
  • I thought about it and this is how I did it to just make it work for now, but I think using QString brings some overhead, doesn't it? So I am searching for a way to avoid it, though if I won't find anything soon, I will simply use QString. – pzaj Jun 25 '17 at 20:46
  • 1
    Because the `QString` stores the strings in Unicode format you'll have one conversion from `std::string` to `QString` and vice versa. – Akira Jun 25 '17 at 21:05
  • I assume using QByteArray will be faster here (my std::string only contains english letters and numbers if that makes any difference). I guess the second conversion comment is just a typo :) Thank you, I will definitely use one of them (depending which one is faster) if I don't find a "direct" solution – pzaj Jun 25 '17 at 21:30
  • 1
    Using `QByteArray` is faster because it handles the `const char*` inside your `std::string` as a raw data and doesn't deal with its content. – Akira Jun 25 '17 at 21:41
  • Good, I'm also not sure if there's any difference, but I just found out you can call `myVariant.toByteArray().constData()`. It seems more explicit to me. – pzaj Jun 25 '17 at 21:55
  • 1
    The `myVariant.toByteArray()` and the `myVariant.value()` eventually [do the same](http://doc.qt.io/qt-5/qvariant.html#value). – Akira Jun 25 '17 at 22:27