علیکمالسلام ؛
قبل از اینکه به پاسخ مستقیم سؤال بپردازیم ، بیاید درک کنیم چه شد که template ها نیاز برنامهنویس شد.
این تابع را در نظر بگیر :
int Sum (const int& first, const int& second){
return first+second;
}
این تابع دو عدد از نوع int دریافت و حاصل جمعشون را بر میگردونه.
خب ! حالا چه میشه اگه شما بخواید به جای int نوع double ارسال کنید ؟ و برنامهی شما با انواع مختلفی داده نیاز داشته باشه که با این تابع کار کنه. شاید بگید خب یک تابع دیگه با پارامتر و نوع بازگشتی double مینویسم.
با این روش چه مشکلاتی پیش میآید :
کد تکراری.
بالا رفتن درصد خطای کد.
افزایش بیدلیل حجم کد.
سخت شدن مدیریت کد.
مشکل در آپدیت کردن سورس کد.
و ...
زبان سیپلاسپلاس برای رفع این مشکلما template ها را معرفی کرده است. template ها میتوانند هر نوع دادهای را قبول کنن. تابع زیر ، تابع template بازنویسی شدهی تابع Sum است که در مثال بالا نوشتیم :
template <typename newType> newType Sum (const newType& first, const newType& second){
return first + second;
}
???خییییلی بزرگ شد ن ؟. خب میتونیم کوتاهش کنیم :
template <typename newType>
newType
Sum (const newType& first, const newType& second){
return first + second;
}
نکته : میدانیم که کامپایلر فاصلههارا نادیده میگیره.
خب ! اوّل برای تبدیل تابع ، به یک تابع template باید از کلمهی کلیدی template استفاده کنیم. و بعد با استفاده از < > اسم نوع دادههای جدیدمان را بنویسیم.
نکته : ما هیچ نوع دادهی جدیدی درواقع تعریف نمیکنیم. این تعریف فقط معرفی یک اسم به عنوان نوع دادهای هست که میتواند به هر چیزی اعم از int,double ,... تبدیل بشود.
و داخل < > ما از کلمهیکلیدی typename برای تعریف اسم داده استفاده کردیم. و همچنین میتوانیم کلمهیکلیدی class نیز استفاده کنیم که هردو برابر یک دیگر هستن. امّا زمانی شما دارید templateی از template درست میکنید. مثلاً این نمونه :
template < template <typename> class MyTmpClass, typename newType>
اینجا دیگه نمیتوانید بین کلمهکلیدی typename و class تفاوت قائع نشید. چرا که نیازه صراحتاً مشخص. امّا در استاندارد ۱۷ این مشکل وجود ندارد ِ؛ ولی بهتر است که این تفاوت را اعمال کنیم.
حال به راحتی میتوانیم تابع را فراخوانی کنیم. به تکه کدزیر توجه کنید
Sum (12 ,32);
Sum (1'000'000'000'000,3212'333'233);
Sum (std::string("ghasem") , std::string("ramezani"));
Sum (12, 32.0);
سه خط اوّل کد بدون مشکل کامپایل میشوند. الا خط آخری. چرا که ما یک پارامتر با نوع int و یک پارامتر با نوع double ارسال کردیم.
برای حل این مشکل بیاید ببینیم که template ها به چه صورت کار میکنند. فرض کنید این تابع را فراخوانی کردیم :
Sum ( int , int );
وقتی کامپایلر به این تابع بر میخورد. تابع template مارا به اینصورت برای ما بازنویسی میکند :
int
Sum (const int& first, const int& second){
return first + second;
}
خب ! و وقتیما سعی میکنیم این تابع را فراخوانی کنیم :
Sum ( int , double );
برنامه کامپایل نمیشود و خطای زیر را ساطع میکنن. چرا که یک پارامتر Int و دیگری double هست.
./main.cpp:5: candidate template ignored: deduced conflicting types for parameter 'newType' ('int' vs. 'double')
آیا این شکل استفاده از توابع براتون آشنا نیست ؟ یه کم فک کنید :
std::vector
std::array
std::list
تمام این کلاسها ، template class هستند. و هر نوعی میتوانند قبول کنند :
#include <vector>
#include <string>
class myClass{
public:
myClass(){}
};
int main (void){
std::vector <int> myIntger {1,2,3,4};
std::vector <std::string> myString {"ghasem" , "ramezani"};
std::vector <myClass> myClassVector;
return 0;
}
نکته : این توضیح خیلی خلاصه از template ها و روش استفاده از آنها بود و به همین دو خط محدود نمیشوند.
و اینکه گفتید "به نظر پیچیده میباشد" ?. پیچیدگی در عین سادگی یکی از قابلیتهای فوقالعادهی زبان سیپلاسپلاسه?. اصلاً کد باید وحشتناک باشه.?