Доброго времени суток! В этой статье я хотел бы рассказать о существующих возможностях строкового форматирования в современном C++, показать свои наработки, которые я уже несколько лет использую в реальных проектах, а также сравнить производительность различных подходов к строковому форматированию. Строковое форматирование — это операция, позволяющая получить результирующую строку из строки-шаблона и набора аргументов. Строка-шаблон содержит текст, в который включены местозаполнители (placeholders), вместо которых подставляются аргументы. Подробнее можно узнать перейдя по ссылке: https://github.com/fi1a/format.
Для наглядности небольшой пример:
int apples = 5;
int oranges = 7;
std::string str = format("I have %d apples and %d oranges, so I have %d fruits", apples, oranges, apples + oranges);
std::cout << str << std::endl;
Здесь:
Строка-шаблон: I have %d apples and %d oranges, so I have %d fruits
Местозаполнители: %d, %d, %d
Аргументы: apples, oranges, apples + oranges
При выполнении примера, получаем результирующую строку
I have 5 apples and 7 oranges, so I have 12 fruits
Теперь посмотрим, что же нам предоставляет C++ для строкового форматирования.
Наследие C
Строковое форматирование в C осуществляется с помощью семейства функций Xprintf. С тем же успехом, мы можем воспользоваться этими функциями и в C++:
char buf[100];
int res = snprintf(buf, sizeof(buf), "I have %d apples and %d oranges, so I have %d fruits", apples, oranges, apples + oranges);
std::string str = "error!";
if (res >= 0 && res < sizeof(buf))
str = buf;
std::cout << str << std::endl;
Это довольно неплохой способ форматирования, несмотря на кажущуюся неуклюжесть:
- это самый быстрый способ строкового форматирования
- этот способ работает практически на всех версиях компиляторов, не требуя поддержки новых стандартов
Но, конечно, не обошлось и без недостатков:
- нужно знать заранее сколько памяти потребуется для результирующей строки, что не всегда возможно определить
- соответствие количества и типа аргументов и местозаполнителей не проверяется при передаче параметров извне (как в обертке над vsnprintf, реализованной ниже), что может привести к ошибкам при выполнении программы
Функция std::to_string()
Начиная с C++11 в стандартной библиотеке появилась функция std::to_string(), которая позволяет преобразовать передаваемое значение в строку. Функция работает не со всеми типами аргументов, а только со следующими:
- Не нашли ответа?Задать вопрос мы подготовим и вышлем вам ответ на e-mail
- Мощная прокачка Инстаграм* аккаунта
- Бесплатные и платные сервисы для раскрутки
- int
- long
- long long
- unsinged int
- unsinged long
- unsigned long long
- float
- double
- long double
Пример использования:
std::string str = "I have " + std::to_string(apples) + " apples and " + std::to_string(oranges) + " oranges, so I have " + std::to_string(apples + oranges) + " fruits";
std::cout << str << std::endl;
Класс std::stringstream
Класс std::stringstream — это основной способ строкового форматирования, который нам предоставляет C++:
std::stringstream ss;
ss << "I have " << apples << " apples and " << oranges << " oranges, so I have " << apples + oranges << " fruits";
std::string str = ss.str();
std::cout << str << std::endl;
Строго говоря, использование std::stringstream не является в полной мере строковым форматированием, так как вместо местозаполнителей мы вставляем в строку-шаблон аргументы. Это допустимо в простейших случаях, но в более сложных существенно ухудшает читаемость кода:
ss << "A[" << i1 << ", " << j1 << "] + A[" << i2 << ", " << j2 << "] = " << A[i1][j1] + A[i2][j2];
сравните с:
std::string str = format("A[%d, %d] + A[%d, %d] = %d", i1, j1, i2, j2, A[i1][j1] + A[i2][j2]);
Объект std::sringstream позволяет реализовать несколько интересных оберток, которые могут понадобится в дальнейшем.
Преобразование «чего угодно» в строку:
template<typename T> std::string to_string(const T &t)
{
std::stringstream ss;
ss << t;
return ss.str();
}
std::string str = to_string("5");
Преобразование строки во «что угодно»:
template<typename T> T from_string(const std::string &str)
{
std::stringstream ss(str);
T t;
ss >> t;
return t;
}
template<> std::string from_string(const std::string &str)
{
return str;
}
int x = from_string<int>("5");
Преобразование строки во «что угодно» с проверкой:
template<typename T> T from_string(const std::string &str, bool &ok)
{
std::stringstream ss(str);
T t;
ss >> t;
ok = !ss.fail();
return t;
}
template<> std::string from_string(const std::string &str, bool &ok)
{
ok = true;
return str;
}
bool ok = false;
int x = from_string<int>("x5", ok);
if (!ok) ...
* Instagram принадлежит компании Meta, признанной экстремистской организацией и запрещенной в РФ, ** Facebook принадлежит компании Meta, признанной экстремистской организацией и запрещенной в РФ, *** Meta Признана экстремистской организацией и запрещена в РФ