Я всегда критиковал ввод-вывод C ++ (особенно форматирование), потому что, на мой взгляд, это шаг назад по отношению к C. Форматы должны быть динамическими и имеют смысл, например, длязагрузить их из внешнего ресурса в виде файла или параметра.
Однако я никогда раньше не пытался реализовать альтернативу, и ваш вопрос заставил меня попытаться потратить несколько часов на эту идею.
Конечно, проблема была более сложной, чем я думал (например, целочисленная процедура форматирования - 200+ строк), но я думаю, что этот подход (строки динамического формата) более пригоден для использования.
Вы можете скачатьмой эксперимент из по этой ссылке (это просто файл .h) и тестовая программа из по этой ссылке (тест, вероятно, не правильный термин, я использовал его, чтобы посмотреть, был ли яможет компилироваться).
Ниже приведен пример
#include "format.h"
#include <iostream>
using format::FormatString;
using format::FormatDict;
int main()
{
std::cout << FormatString("The answer is %{x}") % FormatDict()("x", 42);
return 0;
}
Он отличается от подхода boost.format, поскольку использует именованные параметры и потомуиспользовать строку формата и словарь формата предназначены для создания отдельно (и, например, для передачи).Также я думаю, что параметры форматирования должны быть частью строки (например, printf
), а не в коде.
FormatDict
использует прием для поддержания синтаксиса разумным:
FormatDict fd;
fd("x", 12)
("y", 3.141592654)
("z", "A string");
FormatString
вместо этого просто разбирается с const std::string&
(я решил предварительно разбирать строки формата, но более медленный, но, вероятно, приемлемый подход - просто передавать строку и повторную ее обработку каждый раз).
Форматирование может бытьрасширен для пользовательских типов путем специализации шаблона функции преобразования;например,
struct P2d
{
int x, y;
P2d(int x, int y)
: x(x), y(y)
{
}
};
namespace format {
template<>
std::string toString<P2d>(const P2d& p, const std::string& parms)
{
return FormatString("P2d(%{x}; %{y})") % FormatDict()
("x", p.x)
("y", p.y);
}
}
, после чего экземпляр P2d
может быть просто помещен в словарь форматирования.
Также возможно передать параметры в функцию форматирования, поместив их между %
и {
.
Пока что я реализовал только специализацию целочисленного форматирования, которая поддерживает
- Фиксированный размер с выравниванием по левому / правому краю / центру
- Пользовательский символ заполнения
- Общая база (2-36), нижний или верхний регистр
- Разделитель цифр (с пользовательским символом и счетом)
- Переполнение символа
- Отображение знака
Я также добавил несколько ярлыков для общих случаев, например,
"%08x{hexdata}"
- это шестнадцатеричное число с 8 цифрами, дополненное нулями.
"%026/2,8:{bindata}"
24-разрядное двоичное число (как требуется "/2"
) с разделителем цифр ":"
каждые 8 бит (как требуется ",8:"
).
Обратите внимание, что код является лишь идеей, и дляпример на данный момент я просто запретил копии, когда, вероятно, разумно разрешить историюКак в форматных строках, так и в словарях (однако для словарей важно дать возможность избежать копирования объекта только потому, что его нужно добавить в FormatDict
, и, хотя в IMO это возможно, это также вызывает некоторые нетривиальные проблемы, связанные свремя жизни).
ОБНОВЛЕНИЕ
Я внес несколько изменений в первоначальный подход:
- Строки форматирования теперь можно копировать
- Форматированиедля пользовательских типов это делается с использованием шаблонных классов вместо функций (это допускает частичную специализацию)
- Я добавил форматер для последовательностей (два итератора).Синтаксис все еще грубый.
Я создал для него проект github , с расширенным лицензированием.