Эффективная конкатенация qstring со свёрткой параметров шаблона c++17

Detailed Description

The QStringList class provides a list of strings.

QStringList inherits from QList<QString>. Like QList, QStringList is implicitly shared. It provides fast index-based access as well as fast insertions and removals. Passing string lists as value parameters is both fast and safe.

All of QList’s functionality also applies to QStringList. For example, you can use () to test whether the list is empty, and you can call functions like (), (), (), (), (), (), (), (), and () to modify a QStringList. In addition, QStringList provides a few convenience functions that make handling lists of strings easier:

Adding Strings

Strings can be added to a list using the , () and () functions. For example:

     fonts;
    fonts << "Arial" << "Helvetica" << "Times" << "Courier";

Iterating Over the Strings

To iterate over a list, you can either use index positions or QList’s Java-style and STL-style iterator types:

Indexing:

    for (int i = ; i < fonts.size(); ++i)
         cout << fonts.at(i).toLocal8Bit().constData() << endl;

Java-style iterator:

     javaStyleIterator(fonts);
    while (javaStyleIterator.hasNext())
         cout << javaStyleIterator.next().toLocal8Bit().constData() << endl;

STL-style iterator:

    ::const_iterator constIterator;
    for (constIterator = fonts.constBegin(); constIterator != fonts.constEnd();
           ++constIterator)
        cout << (*constIterator).toLocal8Bit().constData() << endl;

The class is simply a type definition for QListIterator<QString>. QStringList also provide the class which is a type definition for QMutableListIterator<QString>.

Manipulating the Strings

QStringList provides several functions allowing you to manipulate the contents of a list. You can concatenate all the strings in a string list into a single string (with an optional separator) using the () function. For example:

    QString str = fonts.join(", ");
     

The argument to join can be a single character or a string.

To break up a string into a string list, use the () function:

     list;
    list = str.split(',');
     

The argument to split can be a single character, a string, a QRegularExpression or a (deprecated) QRegExp.

In addition, the () function allows you to concatenate two string lists into one. To sort a string list, use the () function.

QString list also provides the () function which lets you to extract a new list which contains only those strings which contain a particular substring (or match a particular regular expression):

     monospacedFonts = fonts.filter(QRegularExpression("Courier|Fixed"));

The () function tells you whether the list contains a given string, while the () function returns the index of the first occurrence of the given string. The () function on the other hand, returns the index of the last occurrence of the string.

Finally, the () function calls () on each string in the string list in turn. For example:

Static Public Members

int ( const QString & s1, const QString & s2, Qt::CaseSensitivity cs )
int ( const QString & s1, const QString & s2 )
int ( const QString & s1, const QLatin1String & s2, Qt::CaseSensitivity cs = Qt::CaseSensitive )
int ( const QLatin1String & s1, const QString & s2, Qt::CaseSensitivity cs = Qt::CaseSensitive )
int ( const QString & s1, const QStringRef & s2, Qt::CaseSensitivity cs = Qt::CaseSensitive )
QString ( const char * str, int size = -1 )
QString ( const char * str, int size = -1 )
QString ( const char * str, int size = -1 )
QString ( const QChar * unicode, int size )
QString ( const std::string & str )
QString ( const std::wstring & str )
QString ( const uint * unicode, int size = -1 )
QString ( const char * str, int size = -1 )
QString ( const ushort * unicode, int size = -1 )
QString ( const wchar_t * string, int size = -1 )
int ( const QString & s1, const QString & s2 )
int ( const QString & s1, const QStringRef & s2 )
QString ( long n, int base = 10 )
QString ( double n, char format = ‘g’, int precision = 6 )
QString ( ulong n, int base = 10 )
QString ( int n, int base = 10 )
QString ( uint n, int base = 10 )
QString ( qlonglong n, int base = 10 )
QString ( qulonglong n, int base = 10 )

Конвертация строк

Класс QString содержит следующие методы: toInt(), toFloat() и toLong(), которые позволяют преобразовать строку в типы int, float и long int соответственно. Метод setNum() позволяет конвертировать различные числовые данные в строку. Данный метод является перегруженным, поэтому компилятор сам позаботиться о том, чтобы вызвать подходящий вариант этого метода. В следующем примере мы конвертируем две строки в целочисленный тип данных, а затем добавляем их. После этого мы уже выполняем обратную конвертацию: из чисел в строки и опять добавляем их.

#include <QTextStream>

int main() {

QTextStream out(stdout);

// Наши строки
QString s1 = «12»;
QString s2 = «15»;
QString s3, s4;

// С помощью метода toInt() конвертируем строки в целочисленный тип данных, а затем добавляем их
out << s1.toInt() + s2.toInt() << endl;

int n1 = 30;
int n2 = 40;

// С помощью метода setNum() выполняем конвертацию из целочисленного типа данных в QString, а затем добавляем их
out << s3.setNum(n1) + s4.setNum(n2) << endl;

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#include <QTextStream>
 

intmain(){

QTextStream out(stdout);

// Наши строки

QString s1=»12″;

QString s2=»15″;

QString s3,s4;

// С помощью метода toInt() конвертируем строки в целочисленный тип данных, а затем добавляем их

out<<s1.toInt()+s2.toInt()<<endl;

intn1=30;

intn2=40;

// С помощью метода setNum() выполняем конвертацию из целочисленного типа данных в QString, а затем добавляем их

out<<s3.setNum(n1)+s4.setNum(n2)<<endl;

return;

}

Результат выполнения программы выше:

Detailed Description

QTextStream can operate on a QIODevice, a QByteArray or a QString. Using QTextStream’s streaming operators, you can conveniently read and write words, lines and numbers. For generating text, QTextStream supports formatting options for field padding and alignment, and formatting of numbers. Example:

QFile data("output.txt");
if (data.open(QFile::WriteOnly | QFile::Truncate)) {
     out(&data);
    out << "Result: " << (10) << left << 3.14 << 2.7;
    
}

It’s also common to use QTextStream to read console input and write console output. QTextStream is locale aware, and will automatically decode standard input using the correct codec. Example:

 stream(stdin);
QString line;
while (stream.readLineInto(&line)) {
    ...
}

Besides using QTextStream’s constructors, you can also set the device or string QTextStream operates on by calling () or (). You can seek to a position by calling (), and () will return true when there is no data left to be read. If you call (), QTextStream will empty all data from its write buffer into the device and call () on the device.

Internally, QTextStream uses a Unicode based buffer, and QTextCodec is used by QTextStream to automatically support different character sets. By default, () is used for reading and writing, but you can also set the codec by calling (). Automatic Unicode detection is also supported. When this feature is enabled (the default behavior), QTextStream will detect the UTF-16 or the UTF-32 BOM (Byte Order Mark) and switch to the appropriate UTF codec when reading. QTextStream does not write a BOM by default, but you can enable this by calling (true). When QTextStream operates on a QString directly, the codec is disabled.

There are three general ways to use QTextStream when reading text files:

  • Chunk by chunk, by calling () or ().
  • Word by word. QTextStream supports streaming into QStrings, QByteArrays and char* buffers. Words are delimited by space, and leading white space is automatically skipped.
  • Character by character, by streaming into QChar or char types. This method is often used for convenient input handling when parsing files, independent of character encoding and end-of-line semantics. To skip white space, call ().

Since the text stream uses a buffer, you should not read from the stream using the implementation of a superclass. For instance, if you have a QFile and read from it directly using () instead of using the stream, the text stream’s internal position will be out of sync with the file’s position.

By default, when reading numbers from a stream of text, QTextStream will automatically detect the number’s base representation. For example, if the number starts with «0x», it is assumed to be in hexadecimal form. If it starts with the digits 1-9, it is assumed to be in decimal form, and so on. You can set the integer base, thereby disabling the automatic detection, by calling (). Example:

 in("0x50 0x20");
int firstNumber, secondNumber;

in >> firstNumber;             
in >> dec >> secondNumber;     

char ch;
in >> ch;                      

QTextStream supports many formatting options for generating text. You can set the field width and pad character by calling () and (). Use () to set the alignment within each field. For real numbers, call () and () to set the notation (, , ) and precision in digits of the generated number. Some extra number formatting options are also available through ().

Like in the standard C++ library, QTextStream also defines several global manipulator functions:

Manipulator Description
Same as (2).
Same as (8).
Same as (10).
Same as (16).
Same as (() | ).
Same as (() | ).
Same as (() | ).
Same as (() & ~).
Same as (() & ~).
Same as (() & ~).
Same as (() | ).
Same as (() | ).
Same as (() & ~).
Same as (() & ~).
Same as ().
Same as ().
Same as ().
Same as ().
Same as ().
Same as operator<<(‘\n’) and ().
Same as ().
Same as ().
Same as ().
Same as (true).

Overview

A shared class consists of a pointer to a shared data block that contains a reference count and the data.

When a shared object is created, it sets the reference count to 1. The reference count is incremented whenever a new object references the shared data, and decremented when the object dereferences the shared data. The shared data is deleted when the reference count becomes zero.

When dealing with shared objects, there are two ways of copying an object. We usually speak about deep and shallow copies. A deep copy implies duplicating an object. A shallow copy is a reference copy, i.e. just a pointer to a shared data block. Making a deep copy can be expensive in terms of memory and CPU. Making a shallow copy is very fast, because it only involves setting a pointer and incrementing the reference count.

Object assignment (with operator=()) for implicitly shared objects is implemented using shallow copies.

The benefit of sharing is that a program does not need to duplicate data unnecessarily, which results in lower memory use and less copying of data. Objects can easily be assigned, sent as function arguments, and returned from functions.

Implicit sharing mostly takes place behind the scenes; the programmer rarely needs to worry about it. However, Qt’s container iterators have different behavior than those from the STL. Read .

In multithreaded applications, implicit sharing takes place, as explained in .

When implementing your own implicitly shared classes, use the QSharedData and QSharedDataPointer classes.

Member Type Documentation

This is a type alias for .

This alias was introduced in Qt 5.10.

See also and .

This is a type alias for .

Alias for . Provided for compatibility with the STL.

This alias was introduced in Qt 5.11.

This is a type alias for .

This alias was introduced in Qt 5.10.

See also and .

This is a type alias for int.

Alias for . Provided for compatibility with the STL.

This alias was introduced in Qt 5.10.

QLatin1String::iterator

This is a type alias for value_type*.

QLatin1String does not support mutable iterators, so this is the same as .

This alias was introduced in Qt 5.10.

See also and .

QLatin1String::reference

This is a type alias for value_type&.

Alias for . Provided for compatibility with the STL.

This alias was introduced in Qt 5.10.

QLatin1String::reverse_iterator

This is a type alias for std::reverse_iterator<iterator>.

QLatin1String does not support mutable reverse iterators, so this is the same as .

This alias was introduced in Qt 5.10.

See also and .

This is a type alias for int.

Alias for . Provided for compatibility with the STL.

This alias was introduced in Qt 5.10.

Handling Plurals

Some translatable strings contain placeholders for integer values and need to be translated differently depending on the values in use.

To help with this problem, developers pass an additional integer argument to the function, and typically use a special notation for plurals in each translatable string.

If this argument is equal or greater than zero, all occurrences of in the resulting string are replaced with a decimal representation of the value supplied. In addition, the translation used will adapt to the value according to the rules for each language.

Example:

int n = messages.count();
showMessage(tr("%n message(s) saved", "", n));

The table below shows what string is returned depending on the active translation:

Active Translation
n No Translation French English
«0 message(s) saved» «0 message sauvegardé» «0 messages saved»
1 «1 message(s) saved» «1 message sauvegardé» «1 message saved»
2 «2 message(s) saved» «2 messages sauvegardés« «2 messages saved»
37 «37 message(s) saved» «37 messages sauvegardés« «37 messages saved»

This idiom is more flexible than the traditional approach; e.g.,

n == 1 ? tr("%n message saved") : tr("%n messages saved")

because it also works with target languages that have several plural forms (e.g., Irish has a special «dual» form that should be used when is 2), and it handles the n == 0 case correctly for languages such as French that require the singular.

To handle plural forms in the native language, you need to load a translation file for this language, too. The lupdate tool has the command line option, which allows the creation of TS files containing only entries with plural forms.

See the Qt Quarterly Article Plural Forms in Translations for further details on this issue.

Instead of , you can use to produce a localized representation of n. The conversion uses the default locale, set using (). (If no default locale was specified, the system wide locale is used.)

A summary of the rules used to translate strings containing plurals can be found in the Translation Rules for Plurals document.

Инициализация строк

Класс QString позволяет инициализировать строки разными способами. Ниже представлен пример с 5-тью различными вариантами инициализации:

#include <QTextStream>

int main() {

QTextStream out(stdout);

// Инициализация №1: Традиционный вариант
QString str1 = «The night train»;
out << str1 << endl;

// Инициализация №2: Объектный способ
QString str2(«A yellow rose»);
out << str2 << endl;

// Инициализация №3
std::string s1 = «A blue sky»;
QString str3 = s1.c_str();
out << str3 << endl;

// Инициализация №4
std::string s2 = «A thick fog»;
QString str4 = QString::fromLatin1(s2.data(), s2.size());
out << str4 << endl;

// Инициализация №5
char s3[] = «A deep forest»;
QString str5(s3);
out << str5 << endl;

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

#include <QTextStream>
 

intmain(){

QTextStream out(stdout);

// Инициализация №1: Традиционный вариант

QString str1=»The night train»;

out<<str1<<endl;

// Инициализация №2: Объектный способ

QString str2(«A yellow rose»);

out<<str2<<endl;

// Инициализация №3

std::strings1=»A blue sky»;

QString str3=s1.c_str();

out<<str3<<endl;

// Инициализация №4

std::strings2=»A thick fog»;

QString str4=QString::fromLatin1(s2.data(),s2.size());

out<<str4<<endl;

// Инициализация №5

chars3=»A deep forest»;

QString str5(s3);

out<<str5<<endl;

return;

}

Результат выполнения программы выше:

Инициализация №3: Инициализация строки с помощью средств стандартной библиотеки C++. Метод c_str() генерирует строку C-style. Данный массив символов, который является классическим способом представления строк в языке C, может быть присвоен объекту класса QString:

std::string s1 = «A blue sky»;
QString str3 = s1.c_str();

1
2

std::strings1=»A blue sky»;

QString str3=s1.c_str();

Инициализация №4: Мы конвертируем стандартную строку C++ в объект класса QString, используя метод fromLatin1(). Данный метод принимает указатель на массив символов, возвращаемый методом . Второй параметр — это размер строки:

std::string s2 = «A thick fog»;
QString str4 = QString::fromLatin1(s2.data(), s2.size());

1
2

std::strings2=»A thick fog»;

QString str4=QString::fromLatin1(s2.data(),s2.size());

Инициализация №5: А это строка в языке C, которая является массивом символов. Один из конструкторов класса QString может принимать массив символов в качестве параметра:

char s3[] = «A deep forest»;
QString str5(s3);

1
2

chars3=»A deep forest»;

QString str5(s3);

Using tr() to Obtain a Translation

The following example shows how a translation is obtained for the class shown in the previous section:

void MainWindow::createMenus()
{
    fileMenu = menuBar()->addMenu(tr("&File"));
    ...

Here, the translation context is because it is the function that is invoked. The text returned by the tr() function is a translation of «&File» obtained from the context.

When Qt’s translation tool, , is used to process a set of source files, the text wrapped in tr() calls is stored in a section of the translation file that corresponds to its translation context.

In some situations, it is useful to give a translation context explicitly by fully qualifying the call to tr(); for example:

QString text = QScrollBar::tr("Page up");

This call obtains the translated text for «Page up» from the context. Developers can also use the () function to obtain a translation for a particular translation context.

Variadic templates

The problem with the current implementation of QStringBuilder is that it implements a container of an arbitrary number of strings through nesting. Each QStringBuilder instance can contain exactly two items – be it strings or other QStringBuilder instances.

This means that all instances of QStringBuilderare a kind of a binary tree in which QStrings are leaf nodes. Whenever something needs to be done on the contained strings, the QStringBuilder needs to process its left sub-tree, then the right sub-tree recursively.

Instead of creating binary trees, we can use variadic templates (available since C++11, which was not available when QStringBuilder was invented). Variadic templates allow us to create classes and functions that have an arbitrary number of template arguments.

This means that, with the help of std::tuplewe can create a QStringBuilder class template that holds as many strings as we want:

When we get a new string to add to theQStringBuilder, we can just addit to the tuple using std::tuple_cat which concatenates two tuples (we’ll be using operator% instead of operator+ as this operator is also supported by QStringand QStringBuilder):

Буквы

Символы можно разделить на несколько категорий: цифры, буквы, пробелы и знаки пунктуации. Напомню, что объекты класса QString состоят из элементов типа QChar. Тип QChar предоставляет нам методы isDigit(), isLetter(), isSpace() и isPunct(). В следующем примере мы, используя небольшую строку, подсчитаем количество цифр, букв, пробелов и знаков пунктуации, входящих в неё:

#include <QTextStream>

int main() {

QTextStream out(stdout);

// Создадим по одной переменной для каждой категории символов
int digits = 0;
int letters = 0;
int spaces = 0;
int puncts = 0;

// Исходная строка
QString str = «7 white, 3 red roses.»;

// Выполняем посимвольный перебор строки
foreach(QChar s, str) {

// Используем необходимые методы для сортировки символов по соответствующим категориям
if (s.isDigit()) {
digits++;
} else if (s.isLetter()) {
letters++;
} else if (s.isSpace()) {
spaces++;
} else if (s.isPunct()) {
puncts++;
}
}

// Выводим результат на экран
out << QString(«There are %1 characters»).arg(str.count()) << endl;
out << QString(«There are %1 letters»).arg(letters) << endl;
out << QString(«There are %1 digits»).arg(digits) << endl;
out << QString(«There are %1 spaces»).arg(spaces) << endl;
out << QString(«There are %1 punctuation characters»).arg(puncts) << endl;

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

#include <QTextStream>
 

intmain(){

QTextStream out(stdout);

// Создадим по одной переменной для каждой категории символов

intdigits=;

intletters=;

intspaces=;

intpuncts=;

// Исходная строка

QString str=»7 white, 3 red roses.»;

// Выполняем посимвольный перебор строки

foreach(QChars,str){

// Используем необходимые методы для сортировки символов по соответствующим категориям

if(s.isDigit()){

digits++;

}elseif(s.isLetter()){

letters++;

}elseif(s.isSpace()){

spaces++;

}elseif(s.isPunct()){

puncts++;

}

}

// Выводим результат на экран

out<<QString(«There are %1 characters»).arg(str.count())<<endl;

out<<QString(«There are %1 letters»).arg(letters)<<endl;

out<<QString(«There are %1 digits»).arg(digits)<<endl;

out<<QString(«There are %1 spaces»).arg(spaces)<<endl;

out<<QString(«There are %1 punctuation characters»).arg(puncts)<<endl;

return;

}

Результат выполнения программы выше:

Detailed Description

The class provides a list of strings.

inherits from QList<>. Like QList, is . It provides fast index-based access as well as fast insertions and removals. Passing string lists as value parameters is both fast and safe.

All of QList’s functionality also applies to . For example, you can use () to test whether the list is empty, and you can call functions like (), (), (), (), (), (), (), (), and () to modify a . In addition, provides a few convenience functions that make handling lists of strings easier:

Adding strings

Strings can be added to a list using the , () and () functions. For example:

     fonts;
    fonts << "Arial" << "Helvetica" << "Times" << "Courier";

Iterating over the strings

To iterate over a list, you can either use index positions or QList’s Java-style and STL-style iterator types:

Indexing:

    for (int i = ; i < fonts.size(); ++i)
         cout << fonts.at(i).toLocal8Bit().constData() << endl;

Java-style iterator:

     javaStyleIterator(fonts);
    while (javaStyleIterator.hasNext())
         cout << javaStyleIterator.next().toLocal8Bit().constData() << endl;

STL-style iterator:

    ::const_iterator constIterator;
    for (constIterator = fonts.constBegin(); constIterator != fonts.constEnd();
           ++constIterator)
        cout << (*constIterator).toLocal8Bit().constData() << endl;

The class is simply a type definition for QListIterator<>. also provide the class which is a type definition for QMutableListIterator<>.

Manipulating the strings

provides several functions allowing you to manipulate the contents of a list. You can concatenate all the strings in a string list into a single string (with an optional separator) using the () function. For example:

    QString str = fonts.join(",");
     

To break up a string into a string list, use the () function:

     list;
    list = str.split(",");
     

The argument to split can be a single character, a string, or a .

In addition, the () function allows you to concatenate two string lists into one. To sort a string list, use the () function.

list also provides the () function which lets you to extract a new list which contains only those strings which contain a particular substring (or match a particular regular expression):

     monospacedFonts = fonts.filter(QRegExp("Courier|Fixed"));

The () function tells you whether the list contains a given string, while the () function returns the index of the first occurrence of the given string. The () function on the other hand, returns the index of the last occurrence of the string.

Finally, the () function calls () on each string in the string list in turn. For example:

Wrap up

This post dealt only with the actual string concatenation. In order to apply this to the real QStringBuilder, we would need a few more things, and the implementation would become a bit overwhelming for reading as a blog post.

We would need to be careful with operator overloading – we would have to use std::enable_iflike the current QStringBuilder implementation to make it work all Qt’s concatenable types and not taint the global space with those operators.

It would also be beneficial to be able to handle temporaries passed to the string concatenation in a safer way as QStringBuilder stores only the references to the strings which, in the case of temporary strings, can easily become dangling references.

Свёртка параметров шаблона и кортежи

Теперь известно, как эффективно объединить коллекцию строк — будь то векторный или пакет параметров с переменным числом элементов.

Проблема в том, что QStringBuilder этого также не имеет. Он хранит строки внутри std::tuple, который не является ни повторяемой коллекцией, ни пакетом параметров.

Для работы со свёрткой параметров шаблона нужны пакеты параметров. Вместо пакета параметров, содержащего строки, можно создать пакет, содержащий список индексов от 0 до n-1, который можно позже использовать с std::getto для доступа к значениям внутри кортежа.

Этот пакет легко создается с помощью the std::index_sequence, который представляет список целых чисел во время компиляции. Можно создать вспомогательную функцию, которая будет принимать std::index_sequence

в качестве аргумента, а затем использовать std::get

(_strings) для доступа к строкам из кортежа одна за другой из сверток параметра шаблона.

template <typename... Strings>
class QStringBuilder {
    using Tuple = std::tuple<Strings...>;
    Tuple _strings;

    template <std::size_t... Idx>
    auto concatenateHelper(std::index_sequence<Idx...>) const
    {
        const auto totalSize = (std::get<Idx>(_strings).size() + ... + 0);

        QString result;
        result.resize(totalSize);

        (result.begin() << ... << std::get<Idx>(_strings));

        return result;
    }
};

Нужно создать функцию-обертку, которая создает индексную последовательность для кортежа, и вызвать функцию c concatenateHelper:

template <typename... Strings>
class QStringBuilder {
    . . .

    auto concatenate() const
    {
        return concatenateHelper(
            std::index_sequence_for<Strings...>{});
    }
};
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector