با معرفی سه نوع داده‌ی جدید به نام‌های std::optional، std::variant و std::any، گام بزرگی در جهت افزایش ایمنی و بیانگری کد برداشت. این سه نوع که به تایپ‌های واژگانی (Vocabulary Types) معروف هستند، هر کدام نیاز رایجی در برنامه‌نویسی را به روشی مدرن و نوع‌ایمن پاسخ می‌دهند . std::optional برای بیان وضعیت «داشتن یا نداشتن مقدار»، std::variant به‌عنوان جایگزینی ایمن برای union و std::any برای ذخیره‌سازی هر نوع داده‌ای، طراحی شده‌اند.

std::optional: بیان صریح وجود یا عدم وجود مقدار

در گذشته، برای نشان‌دادن عدم وجود مقدار، از روش‌های مختلفی مانند استفاده از مقادیر خاص (مثلاً -1 برای یک عدد صحیح) یا اشاره‌گرهای nullptr استفاده می‌شد که هر دو مستعد خطا و تفسیرهای اشتباه بودند . std::optional<T> این مشکل را با ارائه‌ی یک ظرف (Wrapper) ساده و در عین حال قدرتمند حل می‌کند: این ظرف یا یک مقدار از نوع T را در خود دارد، یا اینکه خالی است (std::nullopt) .

این نوع داده، ایده‌آل برای توابعی است که نتیجه‌ی محاسبه ممکن است وجود نداشته باشد. برای مثال، تابعی که یک رشته را به عدد صحیح تبدیل می‌کند، می‌تواند یک std::optional<int> برگرداند. اگر تبدیل موفقیت‌آمیز باشد، عدد مورد نظر بازگردانده می‌شود و در غیر این صورت، std::nullopt برگردانده می‌شود . این رویکرد، برنامه‌نویس را مجبور به بررسی صریح وضعیت با استفاده از متدهایی مانند has_value() یا عملگر * و -> می‌کند و به‌وضوح قصد نویسنده را منتقل می‌سازد. همچنین امکان مقداردهی پیش‌فرض با value_or() فراهم شده است .

std::variant: یک union نوع‌ایمن

std::variant به عنوان یک اتحادیه‌ی نوع‌ایمن (Type-Safe Union) طراحی شده است تا جایگزین union خام و خطرناک زبان C شود . یک variant می‌تواند در هر لحظه مقداری از یکی از انواع تعیین‌شده در یک مجموعه‌ی بسته (Closed Set) را در خود ذخیره کند . به عبارت دیگر، شما لیست انواع مجاز را مشخص می‌کنید و variant تضمین می‌کند که فقط یکی از آن انواع در هر لحظه فعال و معتبر باشد .

برای کار با std::variant، روش‌های مختلفی وجود دارد. تابع std::holds_alternative<T> بررسی می‌کند که آیا variant در حال حاضر حاوی نوع T است یا خیر و std::get<T> مقدار آن را برمی‌گرداند . با این حال، قدرتمندترین روش، استفاده از الگوی ویزیتور (Visitor) با تابع std::visit است. با این روش، یک شیء قابل فراخوانی (مانند یک lambda یا تابع) ارائه می‌دهید که برای هر یک از انواع ممکن در variant، یک رفتار خاص را تعریف می‌کند .

یک مثال کلاسیک، تابعی است که یک رشته را تجزیه کرده و نتیجه را به‌صورت variant<int, double, string> برمی‌گرداند و std::visit برای چاپ آن با قالب مناسب استفاده می‌شود . از std::variant در سناریوهایی مانند پردازش پیام‌های مختلف در یک گذرگاه داده (مثل CAN bus) استفاده می‌شود که هر پیام دارای نوع داده‌ی متفاوتی است .

std::any: ذخیره‌سازی هر نوع داده‌ای

اگر std::variant برای مجموعه‌ای بسته از انواع است، std::any برای مجموعه‌ای باز (Open Set) از انواع طراحی شده است. این نوع داده می‌تواند هر نوع قابل کپی‌شدنی را در خود ذخیره کند، درست مانند یک متغیر از نوع var در زبان‌های داینامیک . به عبارت دیگر، std::any یک ظرف چندمنظوره است که ماهیت داده‌ی درون خود را می‌تواند در زمان اجرا تغییر دهد.

اگرچه این انعطاف‌پذیری بالا جذاب به نظر می‌رسد، اما کاربردهای آن محدودتر است. از std::any زمانی استفاده می‌شود که نوع داده‌ها از پیش قابل پیش‌بینی نبوده و تنوع بالایی دارند، مانند ذخیره‌سازی پارامترهای پیکربندی در یک برنامه . بازیابی مقدار از یک std::any از طریق std::any_cast<T> انجام می‌شود که در صورت عدم تطابق نوع، یک استثنا پرتاب می‌کند . همچنین std::any معمولاً از std::variant کندتر عمل می‌کند، زیرا ممکن است نیاز به تخصیص حافظه‌ی پویا داشته باشد. به همین دلیل، اگر بتوان مجموعه‌ی انواع را محدود کرد، استفاده از std::variant ترجیح داده می‌شود .

جمع‌بندی و انتخاب درست

این سه تایپ جدید در C++17، هر کدام راه‌حلی استاندارد و ایمن برای مسائل رایج برنامه‌نویسی ارائه می‌دهند . انتخاب درست به نیاز شما بستگی دارد: برای بیان «مقدار یا هیچ‌چیز»، از std::optional استفاده کنید. برای داشتن یک نوع اتحادیه که یکی از چند نوع مشخص را در خود جای دهد، std::variant بهترین گزینه است. و در نهایت، برای ذخیره‌سازی هر نوع داده‌ای که از قبل قابل پیش‌بینی نیست، std::any راه‌حل مناسب خواهد بود. این تایپ‌ها با افزایش وضوح و ایمنی کد، شیوه‌ی مدرن برنامه‌نویسی در C++ را به سطح جدیدی ارتقا داده‌اند.

کلیدواژه ها : td::optional-std::variant-std::any-C++17 vocabulary types-تایپ‌های واژگانی C++-نوع‌ایمن در C++-std::optional vs nullptr-std::variant type safe union-استفاده از std::visit-std::any vs variant-مقایسه variant و any-آموزش std::optional-آموزش std::variant-آموزش std::any-مدیریت مقادیر اختیاری در C++-union ایمن در C++