Re[2]: Написать аналог функтора std::hex
От: Тот кто сидит в пруду Россия  
Дата: 19.08.10 19:58
Оценка: 77 (3) +1
Здравствуйте, Erop, Вы писали:

E>1) писать что-то своё в std нехорошо.

E>2) AFAIK, std::hex, как и другие манипуляторы, это просто функция получающая на вход ссылку на поток, и возвращающая её же. Например, std::ios_base& my_hex( std::ios_base& ). Эта функция может что-то сделать с потоком и только. Так что это просто такая форма вызова каких-то методов потока. То есть если ты можешь написать код, который переводит поток в состояние ХХХ, то можешь и написать манипулятор ХХХ, а иначе фигушки.
E>3) АFAIK, опять же, сишные потоки перевести в такое состояние, чтобы выдавались бинарные числа нельзя.
E>4) Но можно захачить. Написать шаблонную проксю, вокруг ссылки на поток, такую, что она будет выводить числа в бинарном виде + шаблонную же функцию-переключалку:
E>template<typename TStream> class CBinStreamProxy {
E>    TStream& stream;
E>public:
E>    CBinStreamProxy( TStream& str ) : stream( str ) {}

E>     CBinStreamProxy& operator << ( int i ) { out( i ); return *this; }
E>     //  тут для всех интегральных типов, либо можно как-то автоматизировать
     
E>     template<typename TArg>
E>     CBinStreamProxy& operator << ( TArg arg ) { stream << arg; return *this; }
E>     //  тут повторяем нужный интерфейс потока. Например преобразование к bool и т. д.
E>private:
E>     template<typename TNumber>
E>     void out( TNumber number ) { /* реализация */ }
E>};

E>enum enum_of_bin { bin };

E>template<typename TStream> CMyProxyStream<TStream> operator << (TStream& dst, enum_of_bin ) { return dst; }


На самом деле не надо никаких проксей, такие вещи делаются вполне стандартно через локали. За вывод чисел отвечает std::num_put. Надо написать его наследника, выводящего в зависимости от флага числа в нужном формате (переписать функции do_put), воткнуть его в локаль вместо std::num_put, выставить эту локаль потоку (вызвав метод imbue). В выставлять/снимать флаг в этом самопальном фасете (далее my_numbin_facet) можно примерно так:

void set_bin_mode(std::basic_ostream<CharType>& s, bool yes)
{
    std::locale loc(s.getloc());
    std::use_facet<my_numbin_facet<CharType> >(loc).set_bin_mode(yes);
    s.imbue(loc);
}


Или, если хочется, проверять наличие нужного фасета с помощью std::has_facet и возвращать ошибку по-другому (use_facet кидает какое-то исключение).
При желании можно, конечно, запихать set_bin_mode в манипулятор, но тут возникает другая проблема — hex и dec про него ничего не знают, обратно переключать не смогут. Придется их тогда тоже переписать — IMHO, овчинка выделки не стоит, потому что при переписывании думаю вылезет еще одна проблема.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.