Есть большущий минус, если захочется локализовать приложение, то такой вариант никак не подойдет. Для этого и придумано семейство printf, с другой стороны С++ не позволяет указать порядок. А вот boost::format это делает с легкостью, многие почему-то боятся boost, но данная библиотека очень сильно экономит время при разработке ПО.
В С++ не бум-бум, но недавно увидел, что с помощью этой библиотеки удачно делаь строку на подстроку через делитель. Может кто-либо подсказать более изящнее решение на отсутствие таких стандартных функций как split; explode etc.?
Use boost::lexical_cast, Luke!
Он на порядок(!) быстрее стрингстрима за счет того, что не требует создания тяжелого объекта. Если не учитывать создание объекта, то он все равно быстрее, хотя уже на десятки процентов.
Вот сэкономьте поцелуи, пробегитесь за пару дней по документации boost, хотя бы просто по общему описанию всех библиотек, чтобы знать когда куда копать.
Угу. Только нужно первый строковый операнд ещё принудительно привести к std::string, т.к. для const char* не определен оператор "+".
Но я впрочем, не об этом. Положим, data1 и data2 имеют сложный тип (пусть это будут экземпляры классов A и B). Тогда имеем:
void func(int id, const A& data1, const B& data2)
{
throw std::runtime_error(std::string("Operation with id = ") + boost::lexical_cast<std::string>(id) + " failed, because data1 (" + boost::lexical_cast<std::string>(data1) + ") is incompatible with data2 (" + boost::lexical_cast<std::string>(data2) + ")");
}
Это сработает, если для A и B определены операторы вывода в поток (<<).
А теперь сравните то же самое с использованием предлагаемого класса MakeString:
void func(int id, const A& data1, const B& data2)
{
throw std::runtime_error(MakeString() << "Operation with id = " << id << " failed, because data1 (" << data1 << ") is incompatible with data2 (" << data2 << ")");
}
По-моему, получилось значительно компактнее, разве нет?
Я просто хочу подчеркнуть, что целью данного топика было представить класс MakeString() в контексте его использования для форматирования строк, а не использование std::stringstream для преобразования типов.
MakeString() позволяет форматировать строку, как если бы она была потоком.
MakeString — 'inplace' конвертер из std::ostream в std::string. Вот в чем суть. Наверное, стоит добавить эти разъяснения в топик.
Боже, зачем вы каждый раз создаете ::std::ostringstream, тем более, если это метод, а не свободная функция?
Ну сделайте вы его членом, да очищайте через ostream.str(::std::string()).
Тому, кто скажет, что это преждевременная оптимизация, я отвечу, что не сделать этого — преждевременная пессимизация, так как перенести 1 строку легко, а искать почему с логами тормозит, а без них нет профилировщиком — бесполезная трата времени получится.
Есть принцип — создавать объекты в наименьшей области видимости. Это говорит компилятору о том, что где нужно, и дальше он сам уже может оптимизировать.
Насчет данного примера — логи тормозят в момент вывода на консоль или в момент записи в лог файл. Поэтому иногда приходится делать их асинхронными, но вот создание временных объекто не тормозило ни разу.
PS. Если вам ну так сильно хочется оптимизровать код — то можно сразу же заменить код фукнции на boost::lexical_cast — он в разы быстрее, и точней отражает сущность нужного нам преобразования.
Если вы так боитесь преждевременной пессимизации в связи с созданием временных переменных, то предлагаю при старте программы выделять массив данных, и потом все переменные использовать как элементы этого массива.
Вы можете шуть сколько угодно, но я натыкался на горло, когда создание стрингстрима тормозило. Конкретно он — тяжелый объект.
Касательно компилятора — оптимизаторы значительно умнее, чем вы, вероятно, думаете, и по CFG спокойно можно понять, где что используется и без областей видимостей, не говорите глупостей.
в качестве альтернативы хитрожопому классу с неявным преобразованием к std::string могу предложить хитрожопый макрос, не использования ради, а забавы для.
Имхо, printf более конкретен.
Первый мне не понравился, в нем нельзя разделители предикатом задавать (мне нужно было ::std::is_punct), а он умеет только массив символов принимаь.
Со вторым все ок.
Он на порядок(!) быстрее стрингстрима за счет того, что не требует создания тяжелого объекта. Если не учитывать создание объекта, то он все равно быстрее, хотя уже на десятки процентов.
Сравнение внизу страницы: www.boost.org/doc/libs/1_47_0/libs/conversion/lexical_cast.htm
Не тратьте поцелуи зря)
boost::lexical_cast(123);
Будьте добры, перепишите мой пример с выбрасыванием исключения с использованием boost::lexical_cast.
Но я впрочем, не об этом. Положим, data1 и data2 имеют сложный тип (пусть это будут экземпляры классов A и B). Тогда имеем:
Это сработает, если для A и B определены операторы вывода в поток (<<).
А теперь сравните то же самое с использованием предлагаемого класса MakeString:
По-моему, получилось значительно компактнее, разве нет?
Я просто хочу подчеркнуть, что целью данного топика было представить класс MakeString() в контексте его использования для форматирования строк, а не использование std::stringstream для преобразования типов.
MakeString() позволяет форматировать строку, как если бы она была потоком.
MakeString — 'inplace' конвертер из std::ostream в std::string. Вот в чем суть. Наверное, стоит добавить эти разъяснения в топик.
Ну а так, для составления сложных строк уже придуман упомянутый выше boost::format, его можно научить и с пользовательскими типами работать.
А я поленился :)
Беда в том, что boost::format, как выяснилось, тоже не умеет автоматически преобразовываться к строке:
throw std::runtime_error(str(boost::format("%2% — %1%") % 1 % 2));
И велосипед не нужен=)
Например так:
Ну сделайте вы его членом, да очищайте через ostream.str(::std::string()).
Тому, кто скажет, что это преждевременная оптимизация, я отвечу, что не сделать этого — преждевременная пессимизация, так как перенести 1 строку легко, а искать почему с логами тормозит, а без них нет профилировщиком — бесполезная трата времени получится.
Насчет данного примера — логи тормозят в момент вывода на консоль или в момент записи в лог файл. Поэтому иногда приходится делать их асинхронными, но вот создание временных объекто не тормозило ни разу.
PS. Если вам ну так сильно хочется оптимизровать код — то можно сразу же заменить код фукнции на boost::lexical_cast — он в разы быстрее, и точней отражает сущность нужного нам преобразования.
Касательно компилятора — оптимизаторы значительно умнее, чем вы, вероятно, думаете, и по CFG спокойно можно понять, где что используется и без областей видимостей, не говорите глупостей.
использование: