برنامه نویسی

انگیزه پشت مفاهیم 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_ifs برای ساخت 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 با جزئیات بیشتر ، نظر خود را رها کنید! یا در اینجا بیشتر بخوانید.

نتیجه گیری

  1. مفاهیم خنک و تمیز و قدرتمند هستند
  2. std::enable_if noice است اما می تواند بسیار کلامی شود
  3. std::variant اگر گفته ها و در حال اجرا در زمان اجرا باشد ، می تواند با نوع مبتنی بر کثیف شود
  4. الگوهای عمومی عالی هستند! اما آنها نمی توانند تخصص جزئی یا محدودیت نوع را تحمل کنند.

سعی کنید از مفاهیم استفاده کنید. آنها آسان هستند و باعث می شوند برای استفاده از C ++ مدرن احساس خوبی داشته باشید.

صلح
-باستردرستر

شرح تصویر

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا