C ++ Украсить basic_stream :: underflow () - PullRequest
1 голос
/ 23 июня 2011

Я хочу расширить поведение объекта basic_streambuf с помощью шаблона декоратора.Вот что я сейчас получил:

template<typename char_type, class traits_type>
class forwarding_basic_streambuf
    : boost::noncopyable,
      public std::basic_streambuf<char_type, traits_type>
{
public:
    typedef std::basic_streambuf<char_type, traits_type> forwarded_type;

    forwarding_basic_streambuf(forwarded_type& fwd_buf)
        : m_fwd(&fwd_buf) { }
    virtual ~forwarding_basic_streambuf() { }

    // locales:
//  std::locale pubimbue(std::locale const& loc);
//      => Calls: imbue(loc) | Returns: Previous value of getloc();
//  std::locale getloc  () const;
//      => Returns: If pubimbue() has ever been called, then the last value of loc supplied, otherwise the
//                  current global locale, locale(), in effect at the time of construction. If called after
//                  pubimbue() has been called but before pubimbue has returned (i.e., from within the call
//                  of imbue()) then it returns the previous value.

    // buffer management and positioning:
//  forwarded_type* pubsetbuf (char_type* s, std::streamsize n); => Returns: setbuf(s, n)
//  pos_type        pubseekoff(off_type off, std::ios_base::seekdir way,
//      std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
//      => Returns seekoff(off, way, which)
//  pos_type        pubseekpos(pos_type sp,
//      std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
//      => Returns: seekpos(sp, which)
//  int             pubsync   (); => Returns: sync()

    // get and put areas:
    // get area:
//  std::streamsize sgetn   (char_type* s, std::streamsize n); => Returns: xsgetn(s, n)

    // put area:
//  std::streamsize sputn(char_type const* s, std::streamsize n); => Returns: xsputn(s, n)

protected:
    // virtual functions:
    // locales:
    virtual void imbue(std::locale const& loc) { this->m_fwd->pubimbue(loc); }

    // buffer management and positioning:
    virtual forwarded_type*  setbuf (char_type* s, std::streamsize n)
        { return this->m_fwd->pubsetbuf(s, n); }
    virtual pos_type         seekoff(off_type off, std::ios_base::seekdir way,
        std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
        { return this->m_fwd->pubseekoff(off, way); }
    virtual pos_type         seekpos(pos_type sp,
        std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
        { return this->m_fwd->pubseekpos(sp, which); }
    virtual int              sync   ()
        { return this->m_fwd->pubsync(); }

    // get and put areas:
    // get area:
    virtual std::streamsize xsgetn(char_type* s, std::streamsize n)
        { return this->m_fwd->sgetn(s, n); }
    virtual int_type        uflow()
        {
            if (traits_type::eq_int_type(this->underflow(), traits_type::eof()))
                return traits_type::eof();
            return this->m_fwd->sgetc();
        }

    // put area:
    virtual std::streamsize xsputn  (char_type const* s, std::streamsize n)
        { return this->m_fwd->sputn(s, n); }
    virtual int_type        overflow(int_type c = traits_type::eof())
        {
            if (traits_type::eq_int_type(c, traits_type::eof()))
                return traits_type::not_eof(c);
            return this->m_fwd->sputc(traits_type::to_char_type(c));
        }

private:
    forwarded_type* m_fwd;
};

Основная цель (в качестве первого шага) состоит в том, чтобы просто перенаправить каждую функциональность на оформленный объект.Таким образом, должна быть возможность использовать этот декоратор даже с указателем на его базовый класс.

Все это прекрасно работает для написания методов, но я не знаю, как обращаться с функцией underflow (), который вызывается из uflow () и sgetc ().

Ответы [ 2 ]

3 голосов
/ 23 июня 2011

Я могу что-то упустить, но твой дизайн не имеет для меня особого смысла.

На мой взгляд, расширение streambuf выполняется путем переопределения защищенного виртуального интерфейса, если вы хотите использовать шаблон декоратора, ваш базовый класс декоратора сделает именно это.

template<typename char_type, class traits_type>
class forwarding_basic_streambuf
    : boost::noncopyable,
      public std::basic_streambuf<char_type, traits_type>
{
public:
    typedef std::basic_streambuf<char_type, traits_type> forwarded_type;

    forwarding_basic_streambuf(forwarded_type& fwd_buf)
        : m_fwd(&fwd_buf) { }
    virtual ~forwarding_basic_streambuf() { }

protected:
   virtual streamsize xsputn ( const char * s, streamsize n ) {
       m_fwd->xsputn(s,n);
   }
   virtual int overflow ( int c) {
       m_fwd->overflow(c);
   }
   // etc.
};

Ваша реальная реализация добавит все необходимые «украшения», например,

template<typename char_type, class traits_type>
class add_timestamp_decorator
    : public forwarding_basic_streambuf<char_type, traits_type>
{
public:
    typedef std::forwarding_basic_streambuf<char_type, traits_type> base_type;

    add_timestamp_decorator(base_type::forwarded_type& fwd_buf)
        : base_type(&fwd_buf) { }
    virtual ~add_timestamp_decorator() { }

protected:
   virtual streamsize xsputn ( const char * s, streamsize n ) {
       // detect and remember when a newline is written
       // before the next char is written output the timestamp
       base_type::xsputn(s, n);
   }
   // etc.
};

, а затем использует его в выходном потоке (псевдокод, для ясности опущены определения шаблонов)

ostream outputstream;
// ....
add_timestamp_decorator decorator = new add_timestamp_decorator(outputstream.rdbuf());
outputstream.rdbuf(decorator);

outputstream << "some lines\ntimestamps will be inserted\n\n";
0 голосов
/ 23 июня 2011

Спецификация описывает uflow() следующим образом (27.6.3.4.3. [15-17]):

  • Требуется: Ограничения те же, что и для underflow (), за исключениемчто символ результата должен быть передан из ожидающей последовательности в резервную копию, и ожидающая последовательность не должна быть пустой перед передачей.
  • Поведение по умолчанию: Вызывает underflow ().Если underflow () возвращает traits :: eof (), возвращает traits :: eof ().В противном случае возвращает значение traits :: to_int_type (* gptr ()) и увеличивает значение следующего указателя для входной последовательности.
  • Возвращает: traits :: eof () для обозначения ошибки.

В C ++ этот вид будет выглядеть следующим образом:

if (traits::eq_int_type(this->underflow(), traits::eof())
    return traits::eof();    
return *fetch_gptr_and_inc();

Мы не можем вызвать underflow() непосредственно для декорированного объекта, потому что он недоступен.Кроме того, мы не хотим получать наш собственный gptr (), а только декорированный.Однако мы можем достичь этого косвенно, позвонив sgetc() и sbumpc:

template<typename char_type, class traits_type>
typename forwarding_basic_streambuf<char_type, traits_type>::int_type
forwarding_basic_streambuf<char_type, traits_type>::uflow()
{   
    if (traits_type::eq_int_type(this->m_fwd->sgetc(), traits_type::eof()))
        return traits_type::eof();
    return this->m_fwd->sbumpc();
}
...