برای کار با std::variant، سه رویکرد اصلی برای دسترسی به مقدار وجود دارد که هر کدام برای سناریوی خاصی طراحی شدهاند. تابع std::holds_alternative یک بررسی ساده و بدون استثنا انجام میدهد که آیا variant در حال حاضر حاوی نوع مشخصشده است یا خیر. std::get مقدار را برمیگرداند و در صورت عدم تطابق نوع، استثنای std::bad_variant_access پرتاب میکند. در مقابل، std::get_if یک اشارهگر به مقدار بازمیگرداند یا در صورت عدم تطابق، nullptr برمیگرداند و امکان بررسی ایمن بدون استثنا را فراهم میسازد .
نکتهی جالب این است که کامپایلرهای مدرن در حالت بهینهسازی، بررسیهای تکراری را حذف میکنند. به عنوان مثال، اگر ابتدا از std::holds_alternative استفاده کنید و سپس std::get را فراخوانی کنید، کامپایلر بررسی دوم را حذف کرده و کد خروجی بهینهای تولید میکند .
متد visit و الگوی ویزیتور
قدرتمندترین ابزار برای کار با std::variant، تابع std::visit است که الگوی ویزیتور را پیادهسازی میکند. این تابع یک شیء قابل فراخوانی (مانند lambda یا تابع) دریافت میکند که برای هر یک از انواع ممکن در variant، یک رفتار خاص را تعریف میکند. از C++26 به بعد، std::visit بهعنوان متد عضوی در خود variant نیز در دسترس است که استفاده از آن را سادهتر میکند .
پیادهسازی std::visit در پسزمینه، یک جدول از اشارهگرهای تابع یا یک ساختار switch با شاخههای متعدد تولید میکند. این روش باعث میشود که فراخوانی std::visit با سرعتی قابل مقایسه با فراخوانی توابع مجازی انجام شود و سربار قابلتوجهی به کد تحمیل نکند .
کلاس کمکی std::monostate
گاهی اوقات با موقعیتی مواجه میشوید که نیاز به یک variant با حالت «خالی» دارید، اما همهی انواع موجود در آن قابل ساخت پیشفرض نیستند. std::monostate یک نوع واحد (Unit Type) است که بهعنوان یک جایخالی (Placeholder) در variant استفاده میشود. اگر یک std::monostate را بهعنوان اولین جایگزین در لیست انواع variant قرار دهید، variant بهطور خودکار قابل ساخت پیشفرض خواهد بود و مقدار اولیهی آن، همان monostate خواهد بود. تمام نمونههای monostate با یکدیگر برابر هستند و این نوع، یک انتخاب عالی برای پیادهسازی وضعیت «بدون مقدار» در variant محسوب میشود .
چالش انواع بازگشتی و راهکارهای آن
یکی از چالشهای پیشرفته در کار با std::variant، تعریف انواع بازگشتی (Recursive Types) است. بهطور مستقیم نمیتوان یک variant
تعریف کرد که به خودش ارجاع دهد، زیرا این کار منجر به یک نوع نامتناهی و
در نتیجه رفتار تعریفنشده میشود. راهحل استاندارد برای این مشکل،
استفاده از std::unique_ptr یا
اشارهگرهای هوشمند مشابه است تا چرخهی بازگشتی را بشکنید. با این روش،
میتوان ساختارهای دادهای مانند درختها یا لیستهای پیوندی را با استفاده
از std::variant پیادهسازی کرد .
کلیدواژه ها : std::variant methods-std::visit C++17-std::holds_alternative-std::get-std::get_if-std::monostate-recursive variant-الگوی ویزیتور در C++-variant bad variant access-دسترسی ایمن به variant-انواع بازگشتی در variant-std::visit performance-C++17 variant advanced-متدهای پیشرفته variant-آموزش std::variant