std::string vs QString

I am writing an application which will eventually be connected to a Qt GUI. In this application, I have a Player class, which will contain information about players, such as name.

Qt offers a QString class for dealing with strings with which I can do the following without any problem:

 
  QString name = "Éloïc";


The std::string is unable to deal with characters such as "É", "ï". Chinese characters are not supported as well. I would like my core class Player to be Qt independent but still be able to deal with such characters. Furthermore, I would like to be able to connect it to Qt further down the road.

How would one go about dealing with this issue? Is there another type I can use?

Thanks
QString converts the const char* data into Unicode using the fromUtf8() function.

In all of the QString functions that take const char* parameters, the const char* is interpreted as a classic C-style '\0'-terminated string encoded in UTF-8.

http://doc.qt.io/qt-5/qstring.html#details


1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <string>
#include <locale>

int main()
{
    const std::string str = u8"Éloïc"; // UTF-8 encoded string literal
    std::cout << "size in bytes: " << str.size() << '\n' ; // 7 multi-byte encoding (five characters, seven bytes)
    
    // to perform i/o, set the locale associated with the stream to a utf-8 locale
    // note: locale names like C.UTF-8 are implementation specific
    std::cout.imbue( std::locale( "C.UTF-8" ) ) ; // imbue a utf-8 local;e
    std::cout << str << '\n' ;
}

http://coliru.stacked-crooked.com/a/6570e7214b12880d
@JLBorges: thanks for your answer.


note: locale names like C.UTF-8 are implementation specific


Would there be a portable solution?
> Would there be a portable solution?

With just the standard library, no. There may not even be a non-portable solution with certain standard library implementations; for instance, with the GNU library under anything other than Linux.

Boost.Locale with the ICU back-end would provide a portable solution.
http://www.boost.org/doc/libs/1_54_0/libs/locale/doc/html/index.html
I thought a bit more about the problem and I think I have found a workaround: would it be advisable to create a "base" player class which would not have a "name" member variable but could eventually be inherited to get the proper "string type", depending on the interface? Something like:

Base STL class (not to be really used directly):
1
2
3
4
5
6
7
8
class Player
{
public:
    // some methods here...

private:
    int rank;
};


Class for console app (not to be used in Qt):
1
2
3
4
5
6
7
8
9
class ConsolePlayer: public Player
{
public:
    // some methods here...

private:
    int rank;
    LocalizedPortableString name; // for example using Boost.Locale
};


Class for Qt usage (not in console app):
1
2
3
4
5
6
7
8
9
class ConsolePlayer: public Player
{
public:
    // some methods here...

private:
    int rank;
    QString name; // for example using Boost.Locale
};


I think this would allow me to keep my app clean of Qt utilities in console mode and still be portable...
That doesn't make any sense. A class that implements basic functionality of the application will have different properties depending on the kind of user interface that's used? To give an extreme example, that would be like if your car's ABS would stop working when you take your stereo out.

If your UI may or may not be able to handle Unicode strings, you just to have your core classes store Unicode strings in a common format that can be read by all potential UI modules. For example, a UTF-8 stored in an std::vector<unsigned char>. If the UI is Qt, you just pass the buffer to fromUtf8(). If the UI is the console, you simply build an std::string directly from the byte values of the buffer. If the name is ASCII, it'll display correctly; if not, it would have displayed incorrectly either way.
Something like this, perhaps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct player // no Qt dependencies
{
     std::string name() const { return name_ ; }
 
     private: std::string name_ ; // utf-8 encoded string

    // ...
};

struct qt_player : player
{
     QString qt_name() const { return QString( name().c_str() ) ; }

     // ...
};
@helios: Thanks for your contribution.

First, I don't understand why the above mentioned solution doesn't make sense.


[...] that would be like if your car's ABS would stop working when you take your stereo out.


I introduce a string element in all derived classes. Both the console mode and the Qt mode get a string element.

Second, I'm not sure I understand how your solution of using a vector of chars is different than simply using a std::string.

Could you please elaborate on this?
I introduce a string element in all derived classes. Both the console mode and the Qt mode get a string element.
Yes, I'm saying that doesn't make sense. I see no reason why Player needs to concern itself with the type of UI that's available. At least, nothing you've said so far suggests that it should.

Second, I'm not sure I understand how your solution of using a vector of chars is different than simply using a std::string.
If you prefer to use an std::string containing the byte values of a UTF-8 buffer, that'll work, too. I'm of the opinion that a UTF-8 buffer is not a string, and an std::string should not contain things that are not strings.
Topic archived. No new replies allowed.