انگیزه پشت مفاهیم C ++ – جامعه dev

C ++ 20 معرفی شد مفاهیمبشر آنها چه هستند؟ چرا باید به آنها اهمیت دهم؟ چگونه از آنها استفاده کنم؟
مفاهیم ابزاری قدرتمند برای کمک به شما در نوشتن کد عمومی با محدودیت های ارزیابی شده در زمان کامپایل است.
این به چه معنی است؟
بیایید بگوییم که من یک کتابخانه درست می کنم و می خواهم تابعی را ایجاد کنم که به کاربران من اجازه می دهد در یک عدد صحیح مفرد ، شناور یا رشته ای در آن عبور کنند.
با این حال ، من نمی خواهم اجازه دهم که آنها در یک بولی عبور کنند.
آیا راهی برای تحقق این کار با نوشتن وجود دارد؟ فقط یک عملکرد؟
بله
ما می توانیم این کار را با الگوها و مفاهیم C ++ انجام دهیم. (با تشکر C ++ 20)
خوب بیایید از همان ابتدا شروع کنیم … قالب ها
الگوهای
خوب ، بگذارید بگوید من کتابخانه ای تهیه می کنم که یک عدد صحیح ، شناور یا رشته را بپذیرد.
یکی از راه های انجام این کار مانند این است که با اضافه بار عملکرد:
#include
void function(int v){
std::cout << "function: " << v << std::endl;
}
void function(double v){
std::cout << "function: " << v << std::endl;
}
void function(std::string v){
std::cout << "function: " << v << std::endl;
}
int main(int argc, char** argv){
function("hi");
function(2);
}
بله ، همه توابع همان کار را انجام می دهند و این کامپایل می کند.
اما چرا باید 3 بار آن را بنویسم ؟؟؟
شما نمی کنید !!!
بیایید از الگوهای برای ساده کردن این کار در یک استفاده کنیم.
#include
template
void function(T v){
std::cout << "function: " << v << std::endl;
}
int main(int argc, char** argv){
function("hi");
function(2);
}
خوب ، بنابراین ما برنامه ای داریم که کار می کند و کامپایل می کند.
کامپایلر می بیند که ما برای “سلام” و 2
بشر
بنابراین هنگام تهیه ، به طور خودکار دو تغییر عملکرد را ایجاد می کند. یکی عدد صحیح را می پذیرد و دیگری رشته را می پذیرد.
اگر یک نوع سوم را معرفی کردم ، بیایید یک دوبل بگوییم ، سپس یک نسخه دوتایی از عملکرد را کامپایل می کند.
فوق العاده باحال!
من می توانم چندین نسخه از عملکرد خود را با کد کمتری با استفاده از قالب ها بنویسم.
من می خواهم توجه داشته باشم که یک راه دیگر وجود دارد که می توانید این کار را انجام دهید. در C ++ 17 و بعد از آن ، انواع پاک کردن نوع وجود دارد. (std::variant
وت std::any
)
این نوع می تواند نگه داشته شود چندگانه انواع متغیرها به طور همزمان. انواع آنها در زمان اجرا بر خلاف زمان کامپایل تعیین می شوند.
داستان کوتاه ، شما می توانید این کار را انجام دهید:
#include
#include
void function(std::variant v){
if(std::holds_alternative(v)){
std::cout << "function: " << std::get(v) << std::endl;
}else{
std::cout << "function: " << std::get<:string>(v) << std::endl;
}
}
int main(int argc, char** argv){
function("hi");
function(2);
}
به نظر من ، این به نظر زشت/کلامی می رسد. همچنین یک بیانیه اضافی در آنجا وجود دارد.
در نتیجه ، من از یک الگوی برای این مورد استفاده می کنم.
نکته خوب در مورد یک نوع این است که می تواند برخلاف یک الگوی کلی ، انواع مجاز را در عملکرد محدود کند.
به عنوان مثال ، فقط در یک عدد صحیح و رشته ای به داخل اجازه می دهد function
بشر
خوب ، عالی! آیا راهی وجود دارد که بتوانیم این کار را با قالب ها انجام دهیم؟
جواب بله است!
ما می توانیم به زودی به روش های انجام این کار نگاه کنیم.
درست قبل از رسیدن به آنجا ، می خواهم محدودیت دیگری از الگوها را به شما نشان دهم.
std::enable_if
C ++ دارد std::enable_if
برای فعال کردن توابع خاص در صورت صحت یک شرط.
std::enable_if
اغلب با قالب ها استفاده می شود.
std::enable_if
همچنین یک نوع قالب بندی شده است. آرگومان الگوی اول شرط و دوم نوع است که در صورت صحت شرط استفاده می شود.
در C ++ ، این مفهومی را به نام معرفی می کند سوتین (خرابی جایگزینی خطایی نیست).
بیایید نمونه ای از این را ببینیم:
#include
#include
template
typename std::enable_if<:is_same int="">::value ||
std::is_constructible<:string t="">::value, void>::type
function(T v){
std::cout << "function: " << v << std::endl;
}
template
typename std::enable_if::value ||
std::is_constructible<:string t="">::value), void>::type
function(T v){
std::cout << "diff function: " << v << std::endl;
}
int main(int argc, char** argv){
function("hi");
function(2);
function(true);
}
خروجی در اینجا:
function: hi
function: 2
diff function: true
بنابراین هر دو std::enable_if
s برای ساخت void
اگر شرایط آنها برای نوع قالب بندی صحیح باشد ، نوع بازگشت را برگردانید.
ما استفاده می کنیم type_traits
در C ++ برای ساختن وضعیت ما. (std::is_same
وت std::is_constructible
)
اگر T
int است یا می تواند به یک رشته ساخته شود ، اولین عملکرد به نوع بازگشت باطل داده می شود.
با این حال ، عملکرد دوم داده می شود نامعتبر نوع بازگشت در نتیجه ، عملکرد توسط کامپایلر دور می شود.
از این رو ، با std::enable_if
ما می توانیم چندین کارکرد داشته باشیم به گونه ای که اگر تعویض نوع با یک عملکرد شکست بخورد ، ممکن است عملکرد دیگری وجود داشته باشد که قابل استفاده باشد.
نه تنها این ، با استفاده std::enable_if
شما می توانید به عملکردهای تخصصی جزئی اجازه دهید. مانند (T
وت std::vector
) همزیستی.
رونق Sfinae حل شد.
خوب ، باحال ، ما می توانیم انواع را محدود کنیم std::enable_if
بشر
اما حتی این زشت به نظر می رسد. اگر شرایط طولانی به نظر برسد ، ما را فعال می کنیم.
آیا راه بهتری وجود دارد که بتوانیم این مسئله را برطرف کنیم؟
مفاهیم
در C ++ 20 ، مفاهیم معرفی شدند.
مفاهیم بسیار جالب هستند.
بیایید مشکلی را که قبلاً با مفاهیم داشتیم حل کنیم. همه چیز مختصر تر می شود.
#include
#include
#include
template
concept ValidType = std::same_as || std::is_constructible_v<:string t="">;
template
void function(T v){
std::cout << "function: " << v << std::endl;
}
template
void function(T v){
std::cout << "diff function: " << v << std::endl;
}
int main(int argc, char** argv){
function("hi");
function(2);
function(true);
}
این نوعی خنک تر و تمیزتر است. نباید 2
برای هر دو کارکرد کار می کنید؟
مفاهیم در اینجا خطایی ایجاد نمی کنند.
در عوض ، کامپایلر محدودترین گزینه را انتخاب می کند ، که اولین عملکرد است.
شما می توانید چندین مفهوم را با هم زنجیر کنید Concept1 || Concept2
یا Concept1 && Concept2
بشر
شما می توانید با مفاهیم دیگر مفاهیم ایجاد کنید:
template
concept IsInt = std::same_as;
template
concept IsString = std::is_constructible_v<:string t="">;
template
concept ValidType = IsInt || IsString;
و همه اینها در زمان کامپایل انجام می شود!
این شکل مدرن مفهوم C ++ Sfinae است.
مفاهیم دست به دست هم می دهند requires
کلمه کلیدی
من نمی خواهم این وبلاگ را خیلی طولانی بسازم ، اما اگر دوست دارید توضیح دهم requires
با جزئیات بیشتر ، نظر خود را رها کنید! یا در اینجا بیشتر بخوانید.
نتیجه گیری
- مفاهیم خنک و تمیز و قدرتمند هستند
-
std::enable_if
noice است اما می تواند بسیار کلامی شود -
std::variant
اگر گفته ها و در حال اجرا در زمان اجرا باشد ، می تواند با نوع مبتنی بر کثیف شود - الگوهای عمومی عالی هستند! اما آنها نمی توانند تخصص جزئی یا محدودیت نوع را تحمل کنند.
سعی کنید از مفاهیم استفاده کنید. آنها آسان هستند و باعث می شوند برای استفاده از C ++ مدرن احساس خوبی داشته باشید.
صلح
-باستردرستر