টেম্পলেট (Templates)
কুকি কাটার (The Cookie Cutter)
কোনো একটি তারকাকৃতির বা তারা (star) আকারের কুকি কাটারের (cookie cutter) কথা কল্পনা করুন। আপনি এতে চকোলেট, চিনি বা জিনজারব্রেডের (gingerbread) মতো যে ময়ান বা ডো-ই (dough) ব্যবহার করুন না কেন, এর আকারটি কিন্তু তারার মতোই (same shape) থাকে, শুধু এদের ভেতরের উপাদানগুলো ভিন্ন (different material) হয়। সি++ (C++)-এ মূলত এই ব্যাপারটিকেই টেম্পলেট (template) বলা হয়。
এক্ষেত্রে আলাদা আলাদা করে maxInt(), maxDouble(), বা maxString() লেখার পরিবর্তে, আপনি চাইলে এখানকার ঠিক একটি (one) টেমপ্লেট ফাংশনকে ব্যবহার করতে পারেন এবং আপনার কাজের ও উপযুক্ত টাইপের (type) ওপর ভিত্তি করে এর কম্পাইলারটিকে (compiler) তার মতো করে একটি সঠিক ভার্সন (right version) তৈরি বা স্ট্যাম্প (stamp) করার সুযোগ দিতে পারেন। এর জন্য মূলত কোনো প্রকার রানটাইম খরচ বা রানটাইম কস্টের (runtime cost) প্রয়োজন পড়ে না — কারণ এটি মূলত এর কম্পাইল টাইমেই (compile time) সকল সমস্যার সমাধান করে থাকে。
ফাংশন টেমপ্লেট (Function Templates)
ফাংশন টেমপ্লেট (function template) হলো মূলত কোনো কিছুর ব্লুপ্রিন্ট (blueprint) বা নকশা। আপনি চাইলে যেকোনো একটি প্লেসহোল্ডার টাইপের (placeholder type) সাহায্যে এটিকে লিখতে পারেন এবং এরপর এর কম্পাইলারটি (compiler) মূলত এর প্রয়োজন অনুযায়ী বিভিন্ন নির্দিষ্ট (concrete) ফাংশন জেনারেট (generates) করে নেবে。
টেম্পলেট ম্যাক্স (max) ফাংশন
টেম্পলেট টাইপের অনুমান বা ডিডাকশন (Template Type Deduction)
সাধারণত আপনাকে নিজের থেকে এর টাইপগুলো লেখার (spell out) প্রয়োজন পড়ে না — এখানকার কম্পাইলারটিই (compiler) মূলত এর আর্গুমেন্টগুলো (arguments) থেকে এগুলোকে বুঝে নেওয়ার বা অনুমান (deduces) করার চেষ্টা করে:
myMax(3, 7)— এখানে কম্পাইলার মূলত দুটিint-কে দেখতে পায়, তাই এটিmyMax<int>-কে তৈরি বা স্ট্যাম্প (stamps) করে নেয়myMax(3.14, 2.72)— এখানে দুটিdoubleরয়েছে, তাই এটিmyMax<double>-কে তৈরি করে নেয়
তবে কখনও কখনও যখন এর টাইপগুলো একে অপরের সাথে সাংঘর্ষিক (conflict) অবস্থায় থাকে (যেমন myMax(3, 2.5) — একটি int এবং একটি double), তখন আপনাকে এটিকে ম্যানুয়ালি বা স্পষ্টভাবে উল্লেখ (specify explicitly) করে দিতে হয়: যেমন myMax<double>(3, 2.5)。
ক্লাস টেমপ্লেট (Class Templates)
টেম্পলেট শুধুমাত্র ফাংশনের (functions) জন্যই নয় — আপনি চাইলে সম্পূর্ণ একটি ক্লাসকেও (classes) টেমপ্লেট করতে পারেন। vector<int>, map<string, int>, এবং এসটিএলের (STL) অন্যান্য সব কন্টেইনারগুলো ঠিক এভাবেই কাজ (works) করে থাকে。
টেম্পলেট স্ট্যাক ক্লাস (Template Stack Class)
টেম্পলেট স্পেশালাইজেশন (Template Specialization)
মাঝেমধ্যেই এর জেনেরিক ভার্সন (generic version) বা সাধারণ ভার্সনটি কোনো একটি নির্দিষ্ট টাইপের (specific type) ওপরে তেমন ভালোভাবে কাজ করতে পারে না। সেক্ষেত্রে আপনি চাইলে এটিকে স্পেশালাইজ (specialize) বা বিশেষায়িত করতে পারেন — অর্থাৎ, অন্য সব সাধারণ জিনিসের জন্য এর জেনেরিক বা সাধারণ ভার্সনটিকে (generic version) বজায় রেখে ওই নির্দিষ্ট টাইপের জন্য আপনি একটি কাস্টম ইমপ্লিমেন্টেশন (custom implementation) প্রদান করতে পারেন。
স্ট্রিং বা string-এর জন্য স্পেশালাইজেশন (Specialization)
টেম্পলেটের সাথে auto (সি++১৪ বা C++14+ থকে শুরু)
ভ্যারিয়াডিক টেমপ্লেট (Variadic Templates) (সংক্ষিপ্তভাবে বা Brief)
সি++১১ (C++11) মূলত বেশ কিছু ভ্যারিয়াডিক টেমপ্লেট বা variadic templates চালু বা introduced করেছে — এই টেমপ্লেটগুলো মূলত যেকোনো সংখ্যক বা নাম্বারের (any number) আর্গুমেন্ট গ্রহণ (accept) করতে বেশ পারদর্শী। std::tuple, std::make_unique, এবং printf-এর মতো ফাংশনগুলো ঠিক এভাবেই কাজ করে থাকে।
template <typename... Args>
void print(Args... args) {
((cout << args << " "), ...);
cout << endl;
}
print(1, "hello", 3.14); // 1 hello 3.14এখানকার এই ...-টি হলো মূলত একটি প্যারামিটার প্যাক (parameter pack)। আর এর ফোল্ড এক্সপ্রেশনটি বা fold expression-টি ((cout << args << " "), ...) মূলত একে প্রতিটি আর্গুমেন্টের (each argument) জন্য প্রসারিত বা expands করে দেয়。
সি++২০ কনসেপ্ট (C++20 Concepts) (সংক্ষিপ্তভাবে বা Brief)
বিভিন্ন কনসেপ্ট (Concepts) মূলত আপনাকে যেকোনো টেমপ্লেট প্যারামিটারগুলোকে কনস্ট্রেইন (constrain) বা সীমাবদ্ধ করার সুযোগ দেয়, যাতে আপনি পৃষ্ঠার পর পৃষ্ঠা বা অগণিত কোনো ক্রিপ্টিক (cryptic) বা অজানা টেমপ্লেট এররের পরিবর্তে একেবারে স্পষ্ট (clear) কিছু এরর মেসেজ পেতে পারেন:
template <typename T>
requires std::integral<T>
T gcd(T a, T b) { return b == 0 ? a : gcd(b, a % b); }
gcd(12, 8); // ওকে বা OK: ইনটিজার (int) মূলত ইনটিগ্রাল বা integral
// gcd(1.5, 2.0); // এরর বা ERROR: ডাবল (double) যে কোনো ইনটিগ্রাল (integral) নয় এমন একটি স্পষ্ট মেসেজ (clear message)আধুনিক সি++ (C++)-এর ক্ষেত্রে এই কনসেপ্টগুলো (Concepts) হলো কোয়ালিটি অফ লাইফ (quality-of-life) বা জীবনযাত্রার মান উন্নত করার অন্যতম একটি বড় উদাহরণ।
এসএফআইএনএই (SFINAE) (উল্লেখ বা Mention)
কনসেপ্টের (concepts) আগে সি++ (C++) মূলত SFINAE বা এসএফআইএনএই ব্যবহার করত (Substitution Failure Is Not An Error) — এটি হলো এমন একটি নিয়ম যেখানে কোনো একটি টেমপ্লেটের ইনস্ট্যান্সিয়েশন (instantiation) বা তৈরি যদি কোনো কারণে ফেইল করে (fails), তবে তার কম্পাইলারটি (compiler) কোনো এরর (error) না দেখিয়ে নীরবেই (silently) অন্যান্য ওভারলোডগুলোতে (overloads) চেষ্টা (tries) করতে থাকে। এটি বেশ ভালোই কাজ করে, তবে এর লেখার ধরন বা সিনট্যাক্সটি (syntax) অত্যন্ত জঘন্য বা কুৎসিত (ugly)। তাই আপনি যদি সি++২০ (C++20) বা তার পরবর্তী কোনো ভার্সন ব্যবহার করে থাকেন, তবে অবশ্যই কনসেপ্ট (concepts) ব্যবহার করার চেষ্টা করবেন。