Строковое форматирование C++ и числовое преобразование
C# имеет хороший статический метод
String.Format(string, params string[]);
который возвращает новую строку с предоставленным форматированием и значениями. Есть ли эквивалент в C++?
Причина в том, что я использую log4cxx и хочу воспользоваться такими макросами, как
LOG4CXX_DEBUG( logger, expr );
который использует оценку короткого замыкания, так что expr никогда не вычисляется, если уровень журнала DEBUG не включен.
В настоящее время в C++ я делаю это так:
CString msg;
msg.Format( formatString, values... );
LOG4CXX_INFO( _logger, msg );
что побеждает цель, так как я должен сначала выделить и отформатировать строку, поэтому эффективность логики короткого замыкания не так высока.
Существует аналогичная проблема при попытке сделать простую регистрацию с числовыми значениями. Это не будет компилироваться:
LOG4CXX_DEBUG( _logger, "the price is " + _some-double_);
Поэтому мне приходится писать что-то вроде этого:
CString asStr;
asStr.Format( "%d", _some-double_ );
LOG4CXX_DEBUG( _logger, "the price is " + asStr );
что снова побеждает цель.
Я совсем не эксперт по С ++, поэтому надеюсь, что более знающие люди могут помочь.
7 ответов
log4cxx принимает параметры потока, как, например, вы можете написать, например:
LOG4CXX_DEBUG( _logger, "the price is " << price );
Вы можете вернуться к C и использовать sprintf
printf(stderr,"The Error(%d) happened(%s)\n",error,errmsg(error));
Boost также имеет формат.
// iostream with boost::format
std::cerr << boost::format("The Error(%d) happened(%s)\n") % error % errmsg(error);
Если вы хотите ярлык
logger && (std::cerr << Stuff); // Where Stuff can be your boost::format
Мой любимый способ сделать inline-форматирование - это библиотека boost.format. Например:
#include <boost/format.hpp>
using namespace boost;
LOG4CXX_INFO( _logger, str(format("cheese it %i, %g") % 1234 % 1.3) );
Это очень удобно для использования переменных аргументов в логировании и макро-функциях.
Используя стандартные библиотеки, невозможно создать форматированную строку без какого-либо выделения памяти с вашей стороны. C++ string
Класс не имеет функции "формат" как таковой, поэтому вы должны использовать stringstream
объект для того, чтобы объединить числа с текстом, но это потребовало бы выделения объекта. Глядя на функции C, как sprintf
нужно выделить char
массив заранее sprintf
не выделяет никакой памяти.
Тем не менее, даже если бы существовала статическая функция, такая как "string::format
"Я сомневаюсь, что вы бы получили большую часть преимущества в скорости перед распределением stringstream
возражать против себя и манипулировать им, учитывая, что статическая функция, скорее всего, будет делать те же вещи в фоновом режиме в любом случае.
Либо используйте библиотеку буст-форматов, либо используйте свою небольшую версию вручную (например, make_string здесь).
Если вы используете Microsoft
CString
class, вы, вероятно, захотите использовать этот помощник:
CString FormatV(LPCTSTR pszFormat, ...);
CString FormatV(LPCTSTR pszFormat, ...)
{
ASSERT(pszFormat != NULL);
va_list args;
va_start(args, pszFormat);
CString str;
str.FormatV(pszFormat, args);
va_end(args);
return str;
}
LOG4CXX_DEBUG( _logger, FormatV("the price is %d", price));
Для стандартных строк существует формат std::format начиная с C++20.
Это не совсем то, что вы просили, а другое решение, ваша главная проблема заключалась в дополнительной работе, когда вы не в режиме отладки.
Вы могли бы просто сделать это
#ifdef _DEBUG
CString msg;
msg.Format( formatString, values... );
#endif
LOG4CXX_INFO( _logger, msg );