1

デコレータ パターンを使用して、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;
};

基本的な目標 (最初のステップとして) は、各機能を装飾されたオブジェクトに単純に転送することです。したがって、このデコレータは、その基本クラスへのポインタでも使用できるはずです。

メソッドの記述にはこれで問題ありませんが、uflow() と sgetc() から呼び出される underflow() 関数の処理方法がわかりません。

4

2 に答える 2

3

何かが欠けているかもしれませんが、あなたのデザインは私にはあまり意味がありません.

私が見たように、a の拡張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";
于 2011-06-23T14:32:35.820 に答える
0

仕様書uflow()には次のように記述されています (27.6.3.4.3.[15-17])。

  • Requires: 制約は 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()ただし、 andを呼び出すことで間接的にこれを実現できます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();
}
于 2011-06-23T15:15:54.107 に答える