2.1 - תבניות והפקת קוד - פתרון
פתרון - הגדרה נגישה או התמחות שנוצרה במפורש¶
בפתרון הראשון הקובץ twice.hpp מכיל את כל ההגדרה:
הקובץ main.cpp יכול להשתמש גם ב־int וגם ב־double, מפני שהמהדר רואה את הגוף בזמן יצירת ההתמחויות. אין צורך בקובץ twice.cpp נוסף עבור התבנית הזאת.
בפתרון השני ה־header נשאר עם declaration, ובסוף twice.cpp מוסיפים:
כל שורה מבקשת מימוש מסוים. אם שורת double חסרה והגוף אינו נגיש לקורא, הכרזה על הקריאה אינה יוצרת את הקוד החסר. סוג הכשל יכול להיות בשלב הלינקוג, ולכן חשוב לקרוא איזה כלי דיווח עליו.
התמחות למערך¶
הקוד הבא הוא תוכנית מלאה:
#include <cstddef>
#include <cstdio>
template<class T>
struct Category {
static const char* label() { return "value"; }
};
template<class T>
struct Category<T*> {
static const char* label() { return "pointer"; }
};
template<class T, std::size_t N>
struct Category<T[N]> {
static const char* label() { return "array"; }
static constexpr std::size_t size = N;
};
int main() {
std::puts(Category<int>::label());
std::puts(Category<int*>::label());
std::puts(Category<int[3]>::label());
static_assert(Category<int[3]>::size == 3);
}
הטיפוס int[3] שונה מ־int*. בניסוי הזה מציינים את הטיפוס ישירות, ולכן המערך אינו עובר התאמה לפרמטר פונקציה שמקבל pointer. זאת הבחנה חשובה כשבהמשך נכתוב פונקציות שמנסות להסיק אורך מערך.
מה ההסקה מבטיחה¶
ב־smaller(1, 2) מוסק int. ב־smaller(1.0, 2.0) מוסק double. בקריאה המעורבת אין T יחיד שההסקה מקבלת משני הפרמטרים לפי החתימה הפשוטה.
ב־smaller
הפתרון מסביר קודם את חוזה ההסקה ורק אחר כך את המימוש שהמהדר מפיק. שינוי שמעלים שגיאת קומפילציה בלי להבין איזו המרה נוספה אינו בדיקה מספקת של קוד גנרי.