التخصيص الكامل
خصّص القوالب لنوع معيّن
التخصيص الكامل درس مجاني في C++ Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C++ Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C++ Academy 4 دروس في المجموع.
مراجعة: القوالب
يتيح القالب لقطعة واحدة من الشيفرة العمل مع أنواع عديدة. وينشئ المترجم نسخة ملموسة لكل نوع تستخدمه.
- تتعامل الصيغة العامة مع كل نوع.
- لكن بعض الأنواع تحتاج أحيانًا إلى معالجة خاصة.
#include <iostream>
template <typename T>
T maxOf(T a, T b) { return a > b ? a : b; }
int main() {
std::cout << maxOf(3, 9) << ' ' << maxOf(2.5, 1.5) << '\n';
return 0;
}ما التخصيص الكامل؟
يوفر التخصيص الكامل تطبيقًا منفصلًا تمامًا لنوع محدد واحد، متجاوزًا القالب العام لهذا النوع وحده.
#include <iostream>
template <typename T>
void describe(T) { std::cout << "some type\n"; }
template <>
void describe(int) { std::cout << "an int\n"; }
int main() {
describe(3.14);
describe(42);
return 0;
}الصياغة
يبدأ التخصيص الكامل بأقواس زاوية فارغة template <>، ويحدد النوع الدقيق داخل التخصيص.
#include <iostream>
template <typename T>
struct TypeName { static const char* get() { return "unknown"; } };
template <>
struct TypeName<bool> { static const char* get() { return "bool"; } };
int main() {
std::cout << TypeName<double>::get() << '\n';
std::cout << TypeName<bool>::get() << '\n';
return 0;
}تخصيص قالب صنف
يمكن تخصيص قوالب الأصناف كاملة، مما يمنح نوعًا ما أعضاءه وسلوكه الخاصين المختلفين عن القالب الأساسي.
#include <iostream>
template <typename T>
struct Storage {
T value;
void show() { std::cout << "value: " << value << '\n'; }
};
template <>
struct Storage<bool> {
bool value;
void show() { std::cout << (value ? "true" : "false") << '\n'; }
};
int main() {
Storage<int> s{5}; s.show();
Storage<bool> b{true}; b.show();
return 0;
}لماذا نخصص؟
يعالج التخصيص الأنواع التي تحتاج إلى منطق مختلف، مثل const char* الذي يحتاج إلى مقارنة السلاسل بدلًا من مقارنة المؤشرات.
#include <iostream>
#include <cstring>
template <typename T>
bool equal(T a, T b) { return a == b; }
template <>
bool equal(const char* a, const char* b) { return std::strcmp(a, b) == 0; }
int main() {
std::cout << std::boolalpha;
std::cout << equal(5, 5) << '\n';
std::cout << equal("hi", "hi") << '\n';
return 0;
}تخصيص عضو واحد
في قالب الصنف، يمكنك تخصيص دالة عضو واحدة فقط لنوع معين، مع إعادة استخدام بقية الأعضاء.
#include <iostream>
template <typename T>
struct Printer {
void print(T v) { std::cout << v << '\n'; }
};
template <>
void Printer<char>::print(char v) {
std::cout << "char: " << v << '\n';
}
int main() {
Printer<int>{}.print(7);
Printer<char>{}.print('A');
return 0;
}المطابقة تتفوق على العام
عندما يوجد تخصيص كامل لنوع مطابق تمامًا، يفضّله المترجم دائمًا على القالب الأساسي.
#include <iostream>
template <typename T>
int rank() { return 0; }
template <>
int rank<double>() { return 99; }
int main() {
std::cout << rank<int>() << ' ' << rank<double>() << '\n';
return 0;
}يجب أن يتبع التخصيص القالب الأساسي
يجب التصريح عن التخصيص بعد ظهور القالب الأساسي، وإلا فلن يجد المترجم شيئًا ليخصصه.
#include <iostream>
template <typename T>
const char* kind() { return "generic"; }
template <>
const char* kind<float>() { return "float"; }
int main() {
std::cout << kind<int>() << ' ' << kind<float>() << '\n';
return 0;
}تخصيص قوالب std
يمكنك تخصيص بعض قوالب المكتبة القياسية، مثل std::hash، لأنواعك الخاصة حتى تعمل مع الحاويات المعتمدة على التجزئة.
#include <iostream>
struct Point { int x, y; };
template <typename T>
struct Hasher { size_t operator()(const T&) { return 0; } };
template <>
struct Hasher<Point> {
size_t operator()(const Point& p) { return p.x * 31 + p.y; }
};
int main() {
Hasher<Point> h;
std::cout << h(Point{2, 3}) << '\n';
return 0;
}تخصيص القيم
يمكن تخصيص معاملات القالب غير النوعية لقيم محددة، وهو أمر مفيد لجداول وقت الترجمة.
#include <iostream>
template <int N>
struct Fib { static const int value = Fib<N-1>::value + Fib<N-2>::value; };
template <>
struct Fib<0> { static const int value = 0; };
template <>
struct Fib<1> { static const int value = 1; };
int main() {
std::cout << Fib<10>::value << '\n';
return 0;
}الحفاظ على اتساق السلوك
ينبغي أن يحافظ التخصيص على العقد المفاهيمي نفسه للقالب الأساسي، وأن يقتصر التغيير على التنفيذ. وإلا فقد يفاجأ مستدعو القالب.
#include <iostream>
template <typename T>
T zero() { return T{}; }
template <>
int zero<int>() { return 0; }
int main() {
std::cout << zero<int>() << ' ' << zero<double>() << '\n';
return 0;
}تحقق سريع
اختبر مدى فهمك لصياغة التخصيص الكامل.
مراجعة
لقد تعلمت التخصيص الكامل:
- يوفر تنفيذًا مخصصًا لنوع واحد محدد بدقة
- يُكتب باستخدام
template <>والنوع المحدد - يفضّل المترجم دائمًا التخصيص المطابق تمامًا
- يعمل مع الدوال والفئات والأعضاء المفردة والقيم المحددة
بعد ذلك، سترى التخصيص الجزئي الذي يطابق أنماط الأنواع.
الأسئلة الشائعة
هل درس «التخصيص الكامل» مجاني؟
نعم — نص درس «التخصيص الكامل» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C++ Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C++ Academy 4 دروس في المجموع.
ماذا ستتعلم في «التخصيص الكامل»؟
خصّص القوالب لنوع معيّن تتمرن على C++ Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C++ Academy؟
لا تُشترط خبرة سابقة. C++ Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.
كم من الوقت يستغرق درس «التخصيص الكامل»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C++ Academy هذا؟
نعم. كل درس في C++ Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- التخصيص الكامل
- التخصيص الجزئي
- SFINAE
- أنماط enable_if