مساء الخير عزيزي القارئ!
هذه المقالة هي الثانية في سلسلة من المقالات المجردة التي سأكتبها عندما قرأت من خلال كتاب سكوت مايرز الأكثر مبيعًا ، الفعال والحديث c ++. سيكون لكل من هذه المقالات دليل منفصل في مشروع تم إنشاؤه خصيصًا على github.com مع أمثلة حية لاستخدام ما نقرأه اليوم.
تكمل هذه المقالة قواعد الاستدلال النوعي من المقالة السابقة ، وتناقش جوانب معينة لاستدلال نوع القالب للحجج التي هي صفيف ووظيفة.
استدلال نوع النمط للصفيف
يحتوي المترجم c ++ على مثل هذه الخاصية التي يتم دائمًا تحويل الصفيف المعلن عنها ، عند تمريره إلى وظيفة قالب مع معلمة تم الإعلان عنها على أنها ليست ارتباطًا ، إلى مؤشر إلى النوع المخزن والعكس صحيح ، إذا تم تعريف المعلمة كرابط ، فلن يتم إجراء هذا التحويل.
وظائف القالب:
بادئ ذي بدء ، سأعطي كود وظائف القالب الذي يستنتج الأنواع المرغوبة ، ثم عملية الاشتقاق نفسها:
template<typename T> void paramDeductInfo(T param, const char *initType) { std::cout << initType << " -> (T param) -> " << type_id_with_cvr<T>().pretty_name() << std::endl; }; template<typename T> void refParamDeductInfo(T ¶m, const char *initType) { std::cout << initType << " -> (T ¶m) -> " << type_id_with_cvr<T>().pretty_name() << std::endl; };
استدلال النوع:
cli::printCaption("TYPE DEDUCTION FOR ARRAY OF CHAR"); char charSeq[] = "Hi everyone!"; paramDeductInfo(charSeq, "char []"); refParamDeductInfo(charSeq, "char []"); cli::printCaption("TYPE DEDUCTION FOR ARRAY OF INT"); int intSeq[] = {1, 2, 3}; paramDeductInfo(intSeq, "int []"); refParamDeductInfo(intSeq, "int []"); cli::printCaption("TYPE DEDUCTION FOR ARRAY OF CLASS A"); class A { } const classASeq[] = {A(), A(), A()}; paramDeductInfo(classASeq, "class A[]"); refParamDeductInfo(classASeq, "class A[]");
يعكس الكود الزائف التالي الإخراج إلى وحدة التحكم في هذه التعليمات:
************************************************************************************************************************ TYPE DEDUCTION FOR ARRAY OF CHAR ************************************************************************************************************************ char [] -> (T param) -> char* char [] -> (T ¶m) -> char [13] ************************************************************************************************************************ TYPE DEDUCTION FOR ARRAY OF INT ************************************************************************************************************************ int [] -> (T param) -> int* int [] -> (T ¶m) -> int [3] ************************************************************************************************************************ TYPE DEDUCTION FOR ARRAY OF CLASS A ************************************************************************************************************************ class A[] -> (T param) -> main::A const* class A[] -> (T ¶m) -> main::A const [3]
مثال 1 - تحليل طول مصفوفة وقت الترجمة
علاوة على ذلك ، يخزن نوع الإخراج للصفيف معلومات حول حجمه ، والتي يمكن استخدامها في وظيفة القالب لمعالجة حجم الصفيف أثناء التجميع أو لإنشاء كود أكثر كفاءة.
لقد استخدمت هذه الميزة في وظيفة printCaption لتحديد طول الرأس المعروض في سطر الأوامر في وقت الترجمة. تافه ، ولكن لطيف.
namespace cli { template<typename T, std::size_t N> constexpr void printCaption(T (&capValue)[N]) { static_assert(N <= 121, "caption length should be less than 120"); std::cout << std::endl << "*******************************************************************************" << std::endl << capValue << std::endl << "*******************************************************************************" << std::endl << std::endl; }; }
دعنا نتحقق مما إذا كان هناك خطأ إذا أدخلنا رأسًا غير ملائم بشكل واضح.
cli::printCaption("123456789 123456789 123456789 123456789 123456789 123456789 123456789" "123456789 123456789 123456789 123456789 123456789 !");
وها أنت من فضلك ، أليس كذلك رائع؟
/...sources/cli.h:12:3: error: static assertion failed: caption length should be less than 120 static_assert(N <= 121, "caption length should be less than 120"); ^~~~~~~~~~~~~
المثال 2 - foreach على صفيف في الذاكرة
أعتقد أن هذا نهج آخر من هذا القبيل قد يبدو مفيدًا إذا كان لدينا حجم صفيف في وقت الترجمة ، فلماذا لا نستخدمه لتنظيم حلقة على مثل هذا الصفيف؟
template<typename T, size_t N, typename F> void forEachOnAnArray(T (&inmemArray)[N], F &callback) { for (int i = 0; i < N; ++i) callback(inmemArray[i]); };
استخدام هذه الوظيفة على النحو التالي:
auto printInt = [](int value) { std::cout << " " << value; }; forEachOnAnArray(intSeq, printInt);
بشكل عام ، لا يقتصر استخدام هذه الميزة على سحب حجم المصفوفة.
اكتب الاستدلال للدالة
الحديث عن الاستدلال النوعي لوظيفة مايرز هو موجز. يذكر بالضبط أنه يتم اختزالها إلى مؤشر بنفس الطريقة التي يتم بها استخدام المصفوفات ، إلا عندما لا يتم الإعلان عن معلمة دالة القالب التي سيتم من خلالها عرض نوع دالتنا كمرجع.
ربما كان يجب أن يتحدث عن نوع من أغلفة القوالب للوظائف ، ولكن أعتقد أن هذا يتجاوز مجرد مسألة الكفاءة الحديثة والحديثة.
نحن ، عزيزي القارئ ، سنعود بالتأكيد إلى هذه القضية!
شكرا واتمنى لك يوما جميلا !!