أليس: لماذا هذا المكان مكان غريب جداً؟
دودو: ولأن جميع الأماكن الأخرى ليست غريبة جداً. يجب أن يكون هناك مكان واحد على الأقل غريب جدًا.
لذلك ، دعونا نلقي نظرة على نص فئة القالب BitSet بهدف تكييفه مع متطلبات MK ، تم تحديد مجالات التحسين الرئيسية في وقت سابق. يمكنك بالطبع أن تكتب صفك الخاص من البداية ، لكن دعونا لا نغفل الفرصة للتعرف على الحلول الجيدة ، لأن مكتبة المحكمة الخاصة بلبنان (لا ينبغي الخلط بينها وبين spl) معروفة منذ زمن طويل وتستخدم في كل مكان. تحتاج أولاً إلى العثور على الكود المصدري ، بعد رحلة قصيرة على الإنترنت ، فتحت الدليل للتو باستخدام جهاز MinGW الخاص بي ، وبحثت عن الملف المطلوب ، الذي أنوي مناقشته مرة أخرى.
في البداية ، نرى ما يزيد قليلاً عن صفحة تحتوي على حقوق الطبع والنشر ونص الترخيص ، فضلاً عن مجموعة متنوعة من التحذيرات - حسنًا ، يمكنك تخطي ذلك ، وهذا مخصص للمحامين. التالي يشمل وأنا أشكر المؤلفين - يرافق كل واحد تعليق حول ما نريد الحصول عليه من كل ملف - كل شخص سيفعل ذلك ، سيكون عمل باحث
إنديانا جونز أسهل. تأتي التعاريف التالية ، لست من المتعصبين في نظافة الكود ولن أجادل - فليكنوا على الفور ورؤية تعريف عدد البتات في وحدة التخزين ، وهي فترة طويلة غير موقعة. متابعةً لمسار التعريفات الزلقة لـ Defines ، أبحث عن تعريف وحدة التخزين الخاصة بي ، والذي يساوي uint8_fast ، على الرغم من أنني أفهم أن هذا لن يكون واضحًا بشكل كافٍ. بالمناسبة ، أحضر على الفور شكراً آخر للمؤلفين على الأسلوب - في نهاية الوحدة التي ينظفونها بعد أن يدمروا تعريفات داخلية - لم أكن حتى آمل أن أرى مثل هذا الشيء في الإنتاج الحديث.
وهنا يبدأ سوء الفهم الخفيف - في البداية يحددون بنية الهيكل المساعدة للقالب _Base_bitset (لماذا بالضبط البنية ، وليس الفئة ، نظرًا لأنهم قابلون للتبادل) ، حيث يحددون نوع تخزين البيانات ويتم تحديده مرة أخرى مباشرةً - نقوم بتغييره إلى منطقتنا. بعد ذلك ، يتم تحديد حالتين من هذا الهيكل الإضافي - لوحدة تخزين واحدة (جيدًا ، وهذا أمر مفهوم ، لزيادة كفاءة الشفرة) وللمثال المنحل دون تخزين على الإطلاق (ربما لمعالجة الأخطاء) ، حتى نلمس هذا الرمز.
بعد ذلك ، نجد bitset للفئة الرئيسية (الآن الفئة) ، والمستمدة من بنية القالب (نعم ، من الممكن في C ، وليس من الواضح سبب القيام بذلك ، ولكن من الممكن) ، حيث يتم تحديد نوع التخزين مرة أخرى وتغييره إلى منطقتنا مرة أخرى. لكنني تساءلت هنا - لماذا لم يتم توارث النوع من الهيكل الأصلي واستغربت أن أجد (نعم بالدهشة ، فصول القالب - هذا ليس ما أقوم به في الحياة اليومية) أن وراثة فئات القوالب مختلفة إلى حد ما عن تلك المألوفة. بمعنى أن الميراث هو نفسه تمامًا وأن جميع كيانات الوالدين متوفرة في فصل البنت (آمل ألا يأخذني أحد إلى صف شوفيني) ، لكن يجب الإشارة إليهم بالاسم الكامل. حسنًا ، لا يزال من الممكن فهم هذا الأمر ، وإلا فلن يختبر المترجم أيًا من الخيارات التي تم إنشاء مثيل لها لتطبيقها ، ولكن إذا كنت تستخدم الأنواع المحددة في الفصل ، فلا تزال بحاجة إلى إضافة الكلمة الأساسية المميزة لـ typename. هذا ليس حلاً واضحًا ، لقد سررت على وجه الخصوص بتشخيص المترجم ، مما يعني "ربما كان لديك نوع من الفئة الأصل" - نعم ، شكرًا ، كابتن ، هذا ما قصدته ، أنا سعيد لأننا نفهم بعضنا البعض ، لكن ليس الأمر أسهل بالنسبة لي. ومع ذلك ، يحدث مثل هذا التشخيص في الإصدار القديم من GCC ، في الرسالة الحالية ، يصبح الأمر أكثر وضوحًا "ربما نسيت الكلمة الرئيسية المكتوبة بالاسم". يعد فهم الرسائل التشخيصية للمترجم لفئات القوالب بشكل عام موضوعًا لأغنية منفصلة ، وهذه الأغنية لا تسعد أبدًا.
لذلك إذا كنا لا نريد استخدام الإنشاءات باستمرار في الفصل الفرعي
std::_Base_bitset<Nb>::_WordT
(ونحن لا نريد ، neg؟) ثم لدينا ثلاث طرق
1) تافهة
#define _WordT typename _Base_bitset<_Nb>::_WordT
2) واضح - تعريف نوع على المستوى العالمي وأنا أحب ذلك أكثر
3) لمحبي غريب
typedef typename _Base_bitset<_Nb>::_WordT _WordT;
(الشعور المستمر لعكاز كروم رائع). شخصيا ، في جميع الحالات الثلاث ، لست سعيدًا بالإشارة المباشرة للفئة الأم ، لأن التنفيذ يجب ألا يأخذ في الاعتبار سلسلة الميراث ، لكن ربما لا أفهم شيئًا ما.
هناك أيضا طريقة 4)
using _WordT = std::_Base_bitset<Nb>::_WordT;
ولكن في الإصدار الخاص بي من المحول البرمجي لا يعمل ، لذلك لا يعمل.
ملاحظة على الهوامش (PNP) - في الكتاب الرائع "C ++ للمبرمجين الحقيقيين" (قمت بتنزيله عن طريق الخطأ في ذلك الوقت ، وقررت أنه تم تخصيصه لـ C ++ في أنظمة الوقت الفعلي) وهو يتحدث عن اللغة "أناقته ليست بأي حال من الأحوال في البساطة (الكلمات C ++ و البساطة تقطع الأذن بتناقضها الواضح) ، ولكن في قدراتها المحتملة. لكل مشكلة قبيحة ، هناك نوع من المصطلحات الذكية ، وهي لغة لغوية أنيقة ، بفضلها تذوب المشكلة أمام أعيننا ". نظرًا لأن الكتاب رائع حقًا ، فهذا يعني أن الاقتباس أعلاه صحيح (أفهم أن هناك امتدادًا منطقيًا معينًا هنا) ، لكن شخصيا ، للأسف ، أرى المشكلة ، لكن هناك ضغطًا مع تعبير ذكي.
على الرغم من الإحساس البسيط بالحيرة الطفيفة ، إلا أن المشكلة تم حلها ويمكنك الاستمتاع بالنتيجة - لكنها لم تكن موجودة. عند تغيير حجم مجموعة الاختبار من 15 إلى 5 ، حدث خطأ في الترجمة بشكل غير متوقع تمامًا. لا ، كل شيء واضح ، تم إنشاء مثيل غير مُعدل مع معلمة القالب 1 ، ولكن يبدو من الخارج غريبًا للغاية - نغير الثابت ويتوقف البرنامج عن التجميع.
يمكنك ، بالطبع ، تعديل هذا التطبيق وآخر ، لكن مثل هذا النهج يشبه الانتهاك الجسيم لمبدأ DRY. هناك أكثر من حل واحد ممكن: 1) الواضح - مرة أخرى التعريف و 2) التافه - مرة أخرى تعريف النوع على المستوى العالمي ، لكنه في هذه الحالة سوف يخرج عن الوحدة ، والذي ، مع ذلك ، يحدث في التنفيذ قيد النظر ، بارز من البنية الأساسية ، ولكن أيضا لن تحتاج إلى التصفيات.
لذلك ، أميل إلى الخيار 3) الفئة الأساسية لتحديد النوع والوراثة لكل المثيلات منه. علاوة على ذلك ، تتم حماية كيانات الفئة الأصل ، مرة أخرى ، بحيث لا تتمسك بها. بعد ذلك اكتشفت خاصية مضحكة ، ربما ينبغي الإشادة بـ C ++ بسبب مرونتها - نظرًا لوجود متغير بدون تخزين ، لا يلزم النوع ، وتسمح اللغة باستخدام التطبيق دون الميراث ، على الرغم من أن هذا ليس ضروريًا بشكل خاص في هذه الحالة بالذات. اكتشفت فورًا عيبًا إضافيًا في المكتبة - في جميع المتغيرات الثلاثة ، يتم تعيين عمليات حساب رقم وحدة التخزين في كل مرة
static size_t _S_whichword
وأقنعة البت فيها _S_maskbit وهي متطابقة تمامًا - نحن أيضًا ننقلها إلى الفئة الأساسية. في هذه الحالة ، يتم اكتشاف رمز "ميت" - طريقة _S_whichbyte ، حتى أنني لا أعرف ماذا أفعل - فمن ناحية ، تتطلب قواعد النغمة الجيدة إزالتها ، من ناحية أخرى - في حالة وجود قالب ، فإن هذا لا يؤثر على الشفرة الناتجة. سأستخدم القاعدة - "لا أفهم شيئًا - لا تلمس" واترك هذه الطريقة.
من حيث المبدأ ، يتم الانتهاء من التعديلات من حيث نوع التخزين ويمكنك البدء في الاختبار. وعلى الفور أجد نقص في التنفيذ - لبنية MSP430 لسبب ما ، يتم تخصيص كلمات ثنائية البايت بدلاً من البايتات. بالطبع ، ليس الكلمات المزدوجة ، كما كان من قبل ، ولكن ما زلنا نقاتل من أجل الحد الأدنى (بكل معنى الكلمة). اتضح أن المحول البرمجي متأكد من أن النوع uint_fast8_t في هذا الهيكل له حجم 2 ، على الرغم من أن نظام الأوامر لديه عمليات مع وحدات البايت وأن المترجم نفسه يستخدمها بالكامل. فكرة استخدام هذا النوع مخترقة ويجب عليك تعيين نوع بيانات uint8_t مباشرة. حسنًا ، إذا كان هناك بنية لم ينجح فيها العمل مع وحدات البايت ، وكان حجم نوع uint_fast8_t مختلفًا عن 1 (لا يوجد أي منها متوفر في المترجم) ، فسيتعين عليه أن يعاني من سرعة جميع الأنواع الأخرى.
يُظهر اختبار الإصدار المصحح تشغيله الصحيح على العديد من البنيات ومعايير مختلفة ، ولكن لا تزال هناك مشكلة في حساب أقنعة بتات لـ MK بدون نوبات مطورة ، وفي حالتنا ، يكون MSP430 و AVR. من حيث المبدأ ، يمكنك ببساطة جعل قراءة قناع البت من المصفوفة طريقة لجميع الحالات ، بغض النظر عن بنية MK. الحل يعمل بشكل جيد ، في البنى المتقدمة مع فهرسة كل شيء على ما يرام ، ولكن لا يزال هناك ضياع للوقت مقارنة بالتحولات السريعة ، لكنني لا أريد أن أصبغ أصابعي بعبارة "الفصل سيكون أسرع" ، قال ، نحن نحسن قال ".
لذلك ، نحتاج إلى تطبيق مختلف لبنيتنا الضعيفة ، والتي تختلف عن جميع الهياكل الأخرى في حجم نوع uint_fast16_t - إنها 2 مقابل 4 ، أو 8 لإصدارات 64 بت. لن يساعدنا التجميع الشرطي ، ولكن تحديد الحالة على أمل التحسين ليس هو طريقة الساموراي ، حيث تظل الأنماط. أحاول إنشاء طريقة قالب للفصل ، لكن التخصص الجزئي غير متاح لها - اتضح أنه يجب أن يكون كذلك وحتى ابحث عن مقالة توضح سبب هذا الحل الجيد. بصراحة ، ما زلت لم أفهم لماذا هذا القرار جيد ، على الأرجح ، وهذا بسبب اعتبارات دينية. ومع ذلك ، لم يتم سؤالنا ، وما الذي يتعين القيام به - يمكنك إنشاء وظيفة قالب ودية (اتضح أنه من المستحيل ، وللسبب نفسه - ممنوع التخصص الجزئي) ، هناك حل آخر ، يبدو مضحكا - التخصص الجزئي للطريقة خارج الجسم من الفصل. يمكنك حتى إنشاء وظيفة قالب منفصلة والوصول إليها من أساليب الفصل ، ولا أعرف الطريقة الأكثر صحة ، لقد اخترت هذه الطريقة. نعم ، ليس لديها إمكانية الوصول إلى الكيانات الداخلية للفصل ، لكن في هذه الحالة بالذات ، ليس من الضروري ، ما الذي يجب فعله إذا لزم الأمر ، لا أعرف حتى الآن ، "سنحل المشكلات عند نشوئها".
الآن لدينا كل ما نحتاجه ، نجمع الأجزاء التي تم اختبارها معًا ونحصل على الكود الذي يحل مشكلة التحسين الأولية. في الوقت نفسه ، جعلنا الكود أكثر إحكاما (وبالتالي أصبح أكثر قابلية للفهم ، على الرغم من أن الأخير قابل للنقاش) ، أزلنا العديد من التكرار وأزلنا الكيانات الزائدة عن الحاجة. الشيء الوحيد الذي لم يتم إصلاحه هو مزيج من الهياكل والطبقات ، ولكن هنا لا أفهم أسباب هذا التنفيذ ، لذلك ، فقط في حالة ، لن أتطرق إلى هذا الجزء.
سيتم تخصيص منشور ثانٍ لتنفيذ النسخة الثانية من المجموعة ، وبدون ذلك تم عمل شيء كثير.