سؤال

لقد كنت أستخدم العائد في العديد من برامج Python الخاصة بي ، وهي حقًا يمسح الرمز في كثير من الحالات. أنا تم التدوين حول هذا الموضوع وهي إحدى صفحات موقعي الشهيرة.

كما يقدم C# العائد-يتم تنفيذه عن طريق حفظ الحالة في جانب المتصل ، يتم من خلال فئة تم إنشاؤها تلقائيًا تحافظ على الحالة ، والمتغيرات المحلية للوظيفة ، إلخ.

أقرأ حاليًا عن C ++ 0x وإضافاتها ؛ وبينما أقرأ عن تنفيذ Lambdas في C ++ 0x ، اكتشفت أنه تم ذلك عبر فئات تم إنشاؤها تلقائيًا أيضًا ، مزودة بمشغل () تخزين رمز Lambda. السؤال الطبيعي الذي تشكل في ذهني: لقد فعلوا ذلك من أجل Lambdas ، لماذا لم يعتبروا ذلك لدعم "العائد" أيضًا؟

بالتأكيد يمكنهم رؤية قيمة المشاركين المشاركين ... لذلك لا يمكنني إلا أن أخمن أنهم يعتقدون أن التطبيقات الماكرو (مثل سيمون تاثام) كبديل كاف. ومع ذلك ، فهي ليست ، لأسباب عديدة: حالة كاليت ، غير المريضة ، القائمة على الماكرو (وحده هو سبب كاف) ، إلخ.

يحرر: yield لا يعتمد على جمع القمامة أو المواضيع أو الألياف. يمكنك قراءة مقالة سيمون لترى أنني أتحدث عن برنامج التحويل البرمجي الذي يقوم بتحول بسيط ، مثل:

int fibonacci() {
    int a = 0, b = 1;
    while (true) {
        yield a;
        int c = a + b;
        a = b;
        b = c;
    }
}

داخل:

struct GeneratedFibonacci {
    int state;
    int a, b;

    GeneratedFibonacci() : state (0), a (0), b (1) {}

    int operator()() {
        switch (state) {
        case 0:
            state = 1;
            while (true) {
                return a;

        case 1:
                int c = a + b;
                a = b;
                b = c;
            }
        }
    }
}

مجموعة القمامة؟ رقم المواضيع؟ رقم الألياف؟ رقم التحول البسيط؟ يمكن القول ، نعم.

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

المحلول

لقد فعلوا ذلك من أجل Lambdas ، لماذا لم يعتبروا ذلك لدعم العائد أيضًا؟

افحص ال أوراق. هل اقترحها أحد؟

... لا يمكنني إلا أن أخمن أنهم يعتبرون التطبيقات الماكرو بديلاً كافيًا.

ليس بالضرورة. أنا متأكد من أنهم يعرفون أن هذه الحلول الكلية موجودة ، لكن استبدالها ليس دافعًا كافيًا ، من تلقاء نفسه ، للحصول على ميزات جديدة.


على الرغم من وجود العديد من المشكلات حول كلمة رئيسية جديدة ، يمكن التغلب عليها باستخدام بناء جملة جديد ، مثل تم القيام به لـ Lambdas واستخدام Auto كنوع إرجاع الوظيفة.

تحتاج الميزات الجديدة بشكل جذري إلى برامج تشغيل قوية (أي الأشخاص) لتحليل الميزات ودفعها بالكامل من خلال اللجنة ، حيث سيكون لديهم دائمًا الكثير من الأشخاص المتشككين في تغيير جذري. لذا ، حتى في غياب ما ستعتبره سببًا تقنيًا قويًا ضد بناء العائد ، فقد لا يزال هناك دعم كافٍ.

ولكن في الأساس ، تبنت مكتبة C ++ القياسية مفهومًا مختلفًا عن المتكررين مما تراه مع العائد. قارن مع تكراري Python ، والتي تتطلب فقط عمليتين:

  1. an_iter.next () إرجاع العنصر التالي أو يثير إيقاف التشغيل (التالي () المضمّن في 2.6 بدلاً من استخدام طريقة)
  2. إرجاع ITER (AN_ITER) AN_ITER (حتى تتمكن من معالجة المواد القابلة للتكرار والتكرار في الوظائف)

يتم استخدام متكررات C ++ في أزواج (والتي يجب أن تكون بنفس النوع) ، مقسمة إلى فئات ، سيكون تحولًا دلاليًا إلى الانتقال إلى شيء أكثر قابلية للبناء ، ولن يتناسب هذا التحول بشكل جيد مع المفاهيم (التي تحتوي على المفاهيم (التي لديها منذ أن تم إسقاطها ، لكن ذلك جاء متأخرا نسبيا). على سبيل المثال ، انظر الأساس المنطقي من أجل (بشكل مبرر ، إذا كان مخيبا للآمال) رفض تعليقي على تغيير المدى للحلقات إلى نموذج من شأنه أن يجعل كتابة هذا الشكل مختلف من التكرار أسهل بكثير.

لتوضيح ما أعنيه بشكل ملموس حول نماذج التكرار المختلفة: يحتاج مثال الرمز الذي تم إنشاؤه اخر اكتب ليكون نوع التكرار بالإضافة إلى الآلات المرتبطة بها للحصول على هذه التكرار والحفاظ عليها. لا يمكن التعامل معها ، لكنها ليست بسيطة كما تتخيل في البداية. التعقيد الحقيقي هو "التحول البسيط" الاحترام للمتغيرات "المحلية" (بما في ذلك أثناء البناء) ، والسيطرة على عمر المتغيرات "المحلية" في النطاقات المحلية داخل المولد (سيحتاج معظمهم إلى حفظها عبر المكالمات) ، وما إلى ذلك.

نصائح أخرى

لا أستطيع أن أقول لماذا لم يضيفوا شيئًا كهذا ، لكن في حالة Lambdas ، لم يكونوا فقط يضاف إلى اللغة أيضًا.

بدأوا الحياة كتطبيق مكتبة في Boost ، والتي أثبتت ذلك

  • تعتبر Lambdas مفيدة على نطاق واسع: سيستخدمها الكثير من الأشخاص عندما يكونون متاحين ، وذاك
  • إن تطبيق المكتبة في C ++ 03 يعاني من عدد من أوجه القصور.

بناءً على ذلك ، قررت اللجنة تبني بعض الأنواع من lambdas في C ++ 0x ، وأعتقد أنهم جربوا في البداية إضافة المزيد من ميزات اللغة العامة للسماح أفضل تنفيذ المكتبة من Boost.

وفي النهاية ، جعلوها ميزة لغة أساسية ، لأنهم لم يكن لديهم خيار آخر: لأنه لم يكن من الممكن عمل أ جيد بما فيه الكفاية تنفيذ المكتبة.

لم تتم إضافة ميزات اللغة الأساسية الجديدة ببساطة إلى اللغة لأنها تبدو فكرة جيدة. اللجنة جداً يتردد في إضافتها ، والميزة المعنية حقًا يحتاج إلى إثبات نفسه. يجب أن يظهر أن الميزة هي:

  • من الممكن التنفيذ في المترجم ،
  • ذاهب لحل حاجة حقيقية ، و
  • أن تطبيق المكتبة لن يكون جيدًا بما فيه الكفاية.

في الحالة إذا أ yield الكلمة الرئيسية ، نعلم أنه يمكن حل النقطة الأولى. كما أظهرت ، إنه تحول بسيط إلى حد ما يمكن القيام به ميكانيكيا.

النقطة الثانية صعبة. كم من أ بحاجة إلى لأن هذا هناك؟ ما مدى استخدام تطبيقات المكتبة الموجودة على نطاق واسع؟ كم عدد الأشخاص الذين طلبوا هذا ، أو قدموا مقترحات لذلك؟

يبدو أن النقطة الأخيرة تمر أيضًا. على الأقل في C ++ 03 ، يعاني تطبيق المكتبة من بعض العيوب ، كما أشرت ، والتي استطاع تبرير تنفيذ اللغة الأساسية. هل يمكن إجراء تنفيذ أفضل للمكتبة في C ++ 0x؟

لذلك أظن أن المشكلة الرئيسية هي حقًا عدم الاهتمام. C ++ هي بالفعل لغة ضخمة ، ولا أحد يريد أن ينمو أكبر ما لم تتم إضافته حقًا يستحق كل هذا العناء. أظن أن هذا ليس مفيدًا بما فيه الكفاية.

يعد إضافة كلمة رئيسية أمرًا صعبًا دائمًا ، لأنه يبطل الرمز الصحيح مسبقًا. تحاول تجنب ذلك بلغة مع قاعدة رمز كبيرة مثل C ++.

تطور C ++ هو عملية عامة. إذا كنت تشعر yield يجب أن يكون هناك ، قم بصياغة طلب مناسب إلى اللجنة القياسية C ++.

سوف تحصل على إجابتك مباشرة من الأشخاص الذين اتخذوا القرار.

لذلك يبدو أنه لم يصل إلى C ++ 11 ، أو C ++ 14 ، ولكن قد يكون في طريقه إلى C ++ 17. ألق نظرة على المحاضرة C ++ coroutines ، تجريد سلبي النفقات العامة من CPPCON2015 والورقة هنا.

لتلخيص ، يعملون على تمديد وظائف C ++ للحصول على عائد وانتظار ميزات الوظائف. يبدو أن لديهم تطبيقًا أوليًا في Visual Studio 2015 ، لست متأكدًا مما إذا كان Clang لديه تطبيق حتى الآن. كما يبدو أنه قد يكون بعض المشكلات في استخدام العائد والانتظار ككلمات رئيسية.

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

يمكن العثور على اقتراح الوظائف القابلة للاستئناف لـ C ++ هنا.

بشكل عام ، يمكنك تتبع ما يحدث بواسطة أوراق اللجنة, ، على الرغم من أنه من الأفضل متابعة التعقب بدلاً من البحث عن مشكلة محددة.

شيء واحد يجب تذكره حول لجنة C ++ هو أنها لجنة تطوعية ، ولا يمكنها تحقيق كل ما تريد. على سبيل المثال ، لم تكن هناك خريطة من نوع التجزئة في المعيار الأصلي ، لأنهم لم يتمكنوا من تحقيق ذلك في الوقت المناسب. يمكن أن يكون هناك أحد في اللجنة يهتم بما يكفي yield وماذا يفعل للتأكد من إنجاز العمل.

أفضل طريقة لمعرفة ذلك هي أن تسأل عضوًا نشطًا في اللجنة.

حسنًا ، لمثل هذا المثال التافهة ، فإن المشكلة الوحيدة التي أراها هي ذلك std::type_info::hash_code() لم يحدد constexpr. أعتقد أن التنفيذ المطابق لا يزال من الممكن أن يجعله كذلك ودعم هذا. على أي حال ، فإن المشكلة الحقيقية هي الحصول على معرفات فريدة ، لذلك قد يكون هناك حل آخر. (من الواضح أنني استعارت بنية "Switch Master Switch" ، شكرًا.)

#define YIELD(X) do { \
    constexpr size_t local_state = typeid([](){}).hash_code(); \
    return (X); state = local_state; case local_state: ; } \
while (0)

الاستخدام:

struct GeneratedFibonacci {
    size_t state;
    int a, b;

    GeneratedFibonacci() : state (0), a (0), b (1) {}

    int operator()() {
        switch (state) {
        case 0:
            while (true) {
                YIELD( a );
                int c = a + b;
                a = b;
                b = c;
            }
        }
    }
}

حسنًا ، سيحتاجون أيضًا إلى ضمان أن التجزئة ليست 0. لا يوجد biggie هناك أيضًا. و DONE الماكرو سهل التنفيذ.


المشكلة الحقيقية هي ما يحدث عند العودة من نطاق مع الأشياء المحلية. لا يوجد أمل في حفظ إطار المكدس بلغة قائمة على C. يتمثل الحل في استخدام Coroutine الحقيقي ، ويعالج C ++ 0x مباشرة مع مؤشرات الترابط والعقود الآجلة.

النظر في هذا المولد/coroutine:

void ReadWords() {
    ifstream f( "input.txt" );

    while ( f ) {
        string s;
        f >> s;
        yield s;
    }
}

إذا تم استخدام خدعة مماثلة ل yield, f تم تدميره في الأول yield, ، ومن غير القانوني مواصلة الحلقة بعد ذلك ، لأنك لا تستطيع ذلك goto أو switch بعد تعريف كائن غير بود.

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

فيما يتعلق بالمعايير ، كان من الممكن أن يساعد C ++ في دعم Coroutine من خلال تحسين مواصفات إطارات المكدس.

في الواقع ، فإن "إضافة" إلى اللغة لا يبدو فكرة جيدة بالنسبة لي ، لأن ذلك من شأنه أن يلتزم بك بتنفيذ "جيد بما فيه الكفاية" لمعظم الحالات التي تعتمد على المترجم بالكامل. بالنسبة للحالات التي يستخدم فيها استخدام Coroutine ، هذا غير مقبول على أي حال

أتفق مع potatoswatter أولاً.

لدعم Coroutine ليس هو نفسه دعم Lambdas وليس ذلك تحول بسيط مثل لعب مع جهاز داف.

انت تحتاج كوروتين غير متماثل كامل (مكتسب) للعمل مثل المولدات في بيثون. تنفيذ سيمون تاثام و كريس كلاهما بدون تكديس Boost.Coroutine هو واحد مكتوه على الرغم من أنه ثقيل.

لسوء الحظ ، لا يزال C ++ 11 ليس لديه yield بالنسبة إلى coroutines حتى الآن ، ربما C ++ 1y ؛)

ملاحظة: إذا كنت تحب حقًا المولدات على طراز Python ، فأراقبها هذه.

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