Есть сервер. на этот сервер приходит туева хуча телеграмм вида XXXX-XXX-XXXXX XXXX XXX... -XXX-XXX и так далее. Здесь тире теоретически должно выступать в качестве разделителя полей и большую часть времени так оно и есть... НО... стоит в сообщении появиться составной фамилии или географическому пункту типа Люберцы-1 и автоматический парсинг откидывает копыта и испускает дух... Мне кроме составления списка известных исключений в голову ничего не приходит... мб есть варианты?
Причём он ещё и активно прокомментирован XD
users.livejournal.com Картинку тут наверное уже все видели но я таки настойчиво рекомендую почитать ещё и первые комменты :)
DON'T. DO. THAT.
Установка : проблема возникла при попытке реализовать Level-Of-Detail при выводе объектов
на QGraphicsScene (отсюда параметры функций).
Первой идеей было написать специализацию структуры отрисовщика под каждый уровень и вызывать их один из другого,
template<class T, class D, int K = 0>
struct LODPaintFunc<T,D,0>
{
inline static void Execute(T controller, QGraphicsItem item, QPainter painter, const QStyleOptionGraphicsItem option, QWidget * widget){}
}
;
...
template<class T, class D>
struct LODPaintFunc<T,D,5>
{
inline static void Execute(T controller, QGraphicsItem item, QPainter painter, const QStyleOptionGraphicsItem option, QWidget * widget)
{
LODPaintFunc<T,D,0>::Execute(controller, item, painter,option, widget);
LODPaintFunc<T,D,1>::Execute(controller, item, painter,option, widget);
LODPaintFunc<T,D,2>::Execute(controller, item, painter,option, widget);
...
}
}
но это работает только если каждый следующий уровень добавляет к предыдущему.
Если требуется отключить скажем отрисовку третьего уровня в пятом,
то вызов
LODPaintFunc<T,D,5>::Execute(controller, item, painter,option, widget);
уже не сработает так как контроля за разворачивающейся матрёшкой:
LODPaintFunc<T,D,5>::Execute(controller, item, painter,option, widget);
LODPaintFunc<T,D,4>::Execute(controller, item, painter,option, widget);
...
LODPaintFunc<T,D,0>::Execute(controller, item, painter,option, widget);
у нас нет. Функции вызыватся одна из другой и третий уровень никак не исключается.
Попытка прямого вызова в пятом уровне специализаций предыдущих одной за другой не срабатывает по той же причине —
нет способа вызвать четвертый уровень не вызвав третий.
Проблема. Сначала подумалосчь что дизайн УГ и придётся всё переделывать. К счастью у нас есть Boost и в частности
такая штука как enable_if_c. Немного перепишем шаблон
Идея в следующем — отмеряем для функции "запал" и пока он "горит" вложенные функции вызываются. Как только FuseLevel станочится отрицательным — на место любой функции начинает подставляться пустое место. Реализовывается это введением двух дополнительных параметров. Дополнительного специализатора FuselEvel (запал) и плейсхолдера для будущей вставки enable_if_c
template<class T, class D, int K,int FuseLevel = 1, class Enable = void>
struct LODPaintFunc
{
inline static void Execute(T controller, QGraphicsItem item, QPainter painter, const QStyleOptionGraphicsItem option, QWidget * widget)
{
}
};
....
template<class D, class T,int FuseLevel>
struct LODPaintFunc<T,D,5,FuseLevel,typename boost::enable_if_c<(FuseLevel>=0)>::type>
{
inline static void Execute(T controller, QGraphicsItem item, QPainter painter, const QStyleOptionGraphicsItem option, QWidget * widget)
{
}
};
Теперь вызов вложенных уровней можно переписать как:
LODPaintFunc<T,D,0,FuseLevel-1>::Execute(controller, item, painter,option, widget);
LODPaintFunc<T,D,1,FuseLevel-1>::Execute(controller, item, painter,option, widget);
LODPaintFunc<T,D,2,FuseLevel-1>::Execute(controller, item, painter,option, widget);
LODPaintFunc<T,D,4,FuseLevel-1>::Execute(controller, item, painter,option, widget);
Обратите внимание на FuseLevel-1
Теперь при вызове из внешнего кода
LODPaintFunc<T,D,5>::Execute(controller, item, painter,option, widget);
у самой функции fuse будет равен 1 (по умолчанию) и вызов вложенных уровней выполнится,
а вот у вложенных функций вызываемых из LODPaintFunc<T,D,5> fuse будет уже 0 и FuseLevel-1 уже не выполнит условие
typename boost::enable_if_c<(FuseLevel>=0)>::type
в специализации класса и на место где должны бы находиться дальнейшие отсылки вглубь дерева детализации
будет подставлено пустое место.
Цель достигнута — без существенного перепиливания кода архитектура позволила ограничивать глубину вызова уровней детализации. Профит.
Код для медитации (или помидоров) — здесь: codepad.org
MUST.ESCAPE!
codepad.org SFINAE в действии
Вот примерно так теперь выглядит мой код, да :)