سؤال

أريد تحديد فئة MyStream لهذا السبب:

MyStream myStream;
myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;

يعطي الناتج

[blah]123
[blah]56
[blah]78

أساسا، أريد إدراج [blah] في المقدمة، ثم إدراجها بعد كل غير منتهي std::endl?

الصعوبة هنا ليست إدارة المنطق، ولكن الكشف عن التعامل معه std::endl. وبعد هل هناك طريقة أنيقة للقيام بذلك؟

شكرا!

تحرير: لا أحتاج إلى المشورة بشأن إدارة المنطق. أحتاج إلى معرفة كيفية اكتشاف / زيادة الطباعة من std::endl.

هل كانت مفيدة؟

المحلول

ما عليك القيام به هو كتابة المخزن المؤقت دفق الخاص بك:
عندما يتم مسح المخزن المؤقت دفق إخراج أحرف البادئة ومحتوى الدفق.

يعمل Works التالية لأن STD :: Endl يتسبب ما يلي.

1) أضف " n" إلى الدفق.
2) مكالمات تدفق () على الدفق
2A) هذه المكالمات Pubsync () على المخزن المؤقت دفق.
2B) هذا يدعو إلى مزامنة الطريقة الافتراضية ()
2C) تجاوز هذه الطريقة الافتراضية للقيام بالعمل الذي تريده.

#include <iostream>
#include <sstream>

class MyStream: public std::ostream
{
    // Write a stream buffer that prefixes each line with Plop
    class MyStreamBuf: public std::stringbuf
    {
        std::ostream&   output;
        public:
            MyStreamBuf(std::ostream& str)
                :output(str)
            {}
            ~MyStreamBuf() {
                if (pbase() != pptr()) {
                    putOutput();
                }
            }

        // When we sync the stream with the output. 
        // 1) Output Plop then the buffer
        // 2) Reset the buffer
        // 3) flush the actual output stream we are using.
        virtual int sync() {
            putOutput();
            return 0;
        }
        void putOutput() {
            // Called by destructor.
            // destructor can not call virtual methods.
            output << "[blah]" << str();
            str("");
            output.flush();
        }
    };

    // My Stream just uses a version of my special buffer
    MyStreamBuf buffer;
    public:
        MyStream(std::ostream& str)
            :std::ostream(&buffer)
            ,buffer(str)
        {
        }
};


int main()
{
    MyStream myStream(std::cout);
    myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;
}

> ./a.out
[blah]123 
[blah]56 
[blah]78
>

نصائح أخرى

مشغلي التحميل الزائد الخاص بك MyStream يجب على Class تعيين علامة إينت ذاتية مطبوعة مطبوعة.

ثم، إذا تم طباعة الكائن التالي، [blah] يمكن إدراجها أمامها.

std::endl هي وظيفة تأخذ وإعادة مرجع إلى std::ostream. وبعد للكشف عنها تم تحويلها إلى دفقك، يجب عليك التحميل الزائد operator<< بين نوعك ومثل هذه الوظيفة:

MyStream& operator<<( std::ostream&(*f)(std::ostream&) )
{
    std::cout << f;

    if( f == std::endl )
    {
        _lastTokenWasEndl = true;
    }

    return *this;
}

وافق مع نيل على المبدأ.

تريد تغيير سلوك المخزن المؤقت، لأن هذه هي الطريقة الوحيدة لتوسيع iOstreams. endl هل هذا:

flush(__os.put(__os.widen('\n')));

widen إرجاع حرف واحد، لذلك لا يمكنك وضع السلسلة الخاصة بك هناك. put المكالمات putc وهي ليست وظيفة افتراضية وعلى السنانيات أحيانا overflow. وبعد يمكنك اعتراض في flush, ، الذي يستدعي المخزن المؤقت sync. وبعد ستحتاج إلى اعتراض وتغيير جميع أحرف نيولينيا كما هي overflowإد أو يدويا syncإد وتحويلها إلى سلسلة الخاص بك.

تصميم فئة المخزن المؤقت التجاوز أمر مزعج ل basic_streambuf تتوقع الوصول المباشر إلى ذاكرة المخزن المؤقت لها. هذا يمنعك من تمرير طلبات الإدخال / الإخراج بسهولة إلى مقدمة basic_streambuf. وبعد تحتاج إلى الخروج على أحد الأطراف ونفترض أنك تعرف فئة المخزن المؤقت دفق، واستمتاع منه. فيcin و cout ليست مضمونة للاستخدام basic_filebuf, ، بقدر ما أستطيع أن أقول.) بعد ذلك، أضف virtual overflow و sync. وبعد (انظر §27.5.2.4.5 / 3 و 27.5.2.4.2 / 7.) قد يتطلب أداء الاستبدال مساحة إضافية حتى توخي الحذر بتخصيص ذلك في وقت مبكر.

- أو -

مجرد إعلان جديد endl في مساحة الاسم الخاصة بك، أو أفضل، مناور لا يسمى endl على الاطلاق!

بدلا من محاولة تعديل سلوك std::endl, ، ربما يجب عليك إنشاء Streambuf تصفية للقيام بهذه المهمة. جيمس كانز لديه مثال إظهار كيفية إدراج الطابع الزمني في بداية كل خط الإخراج. يجب أن يتطلب تعديل بسيط فقط لتغيير ذلك إلى أي بادئة تريدها على كل سطر.

أنا استخدم مؤشرات الوظائف. يبدو الأمر مرعبا للأشخاص الذين لا يعتادوا على ج، لكنهم أكثر كفاءة بكثير في معظم الحالات. إليك مثال:

#include <iostream>

class Foo
{
public:
    Foo& operator<<(const char* str) { std::cout << str; return *this; }
    // If your compiler allows it, you can omit the "fun" from *fun below.  It'll make it an anonymous parameter, though...
    Foo& operator<<(std::ostream& (*fun)(std::ostream&)) { std::cout << std::endl; }
} foo;

int main(int argc,char **argv)
{
    foo << "This is a test!" << std::endl;
    return 0;
}

إذا كنت تريد حقا يمكنك التحقق من عنوان Endl لتأكيد أنك لا تحصل على بعض وظيفة الفراغ / الفراغ الأخرى، لكنني لا أعتقد أنه يستحق كل هذا العناء في معظم الحالات. أتمنى أن يساعد ذلك.

لا يمكنك التغيير std::endl - كما يشير الاسم إلى أنه جزء من مكتبة C ++ القياسية وسلوكه ثابت. تحتاج إلى تغيير سلوك الدفق نفسه، عندما يتلقى نهاية الخط. شخصيا، لم أفكر في هذا الأمر يستحق الجهد، ولكن إذا كنت ترغب في المغامرة في هذه المنطقة، أوصي بشدة بقراءة الكتاب القياسية C ++ iOStreams & Loales.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top