std::any یک ظرف (Container) نوع‌ایمن و با ارزش‌گذاری (Value Semantics) است که قادر به ذخیره‌سازی یک شیء از هر نوع قابل کپی‌سازی (CopyConstructible) می‌باشد. این نوع داده که در هدر <any> تعریف شده است، به برنامه‌نویس اجازه می‌دهد تا در یک متغیر، مقادیری با تایپ‌های کاملاً متفاوت و از پیش ناشناخته را ذخیره کند. به‌عبارت دیگر، std::any یک مجموعه‌ی باز (Open Set) از انواع را پشتیبانی می‌کند، برخلاف std::variant که با مجموعه‌ای بسته (Closed Set) از انواع سروکار دارد. این ویژگی، آن را به ابزاری قدرتمند برای سناریوهایی مانند لایه‌های واسط (Interfaces) که نیاز به عبور دادن داده‌هایی با نوع ناشناخته دارند، تبدیل کرده است.

نحوه‌ی کار با std::any

کار با std::any بسیار ساده و شهودی است. می‌توان با استفاده از سازنده‌ی پیش‌فرض، یک شیء خالی ساخت یا با انتساب مستقیم یک مقدار، آن را مقداردهی کرد. همچنین، برای ساخت شیء در محل و جلوگیری از کپی‌برداری اضافی، می‌توان از std::make_any استفاده کرد که به‌ویژه برای انواع با سازنده‌های غیرپیش‌فرض کارآمد است. برای بررسی اینکه آیا یک شیء std::any حاوی مقدار است یا خیر، از متد has_value() استفاده می‌شود و متد type() نیز typeid شیء ذخیره‌شده را بازمی‌گرداند.

دسترسی به مقدار: std::any_cast

دسترسی به مقدار ذخیره‌شده در یک std::any از طریق تابع std::any_cast انجام می‌گیرد که یک دسترسی نوع‌ایمن را فراهم می‌آورد. این تابع در دو شکل اصلی ارائه می‌شود: شکل ارزش (Value) که در صورت عدم تطابق نوع، استثنای std::bad_any_cast پرتاب می‌کند و شکل اشاره‌گر (Pointer) که در صورت عدم تطابق، nullptr بازمی‌گرداند. در شکل ارزش، می‌توان به‌صورت مقدار، مرجع (Reference) یا مرجع rvalue به داده دسترسی پیدا کرد که این انعطاف‌پذیری، امکان خواندن و تغییر مقدار را به‌صورت کارآمد فراهم می‌سازد.

عملیات‌های کلیدی: reset، swap و make_any

برای مدیریت محتوای std::any، چند عملیات کلیدی وجود دارد که هرکدام کاربرد مشخصی دارند. متد reset شیء را به حالت خالی بازمی‌گرداند و مقدار موجود را نابود می‌کند. متد swap محتوای دو شیء any را با یکدیگر مبادله می‌کند. همچنین، تابع کمکی std::make_any راهی ساده و مطمئن برای ساخت شیء any با استفاده از سازنده‌های مختلف، از جمله سازنده‌های دریافت‌کننده‌ی initializer_list، ارائه می‌دهد.

مزایا، معایب و راهنمای انتخاب

مهم‌ترین مزیت std::any، انعطاف‌پذیری بی‌نظیر آن در ذخیره‌سازی هر نوع داده‌ای است که آن را برای سناریوهای خاصی مانند نوشتن کتابخانه‌های عمومی یا واسط‌های پویا ایده‌آل می‌سازد. با این حال، این انعطاف‌پذیری با هزینه‌هایی همراه است. اولین هزینه، کاهش عملکرد احتمالی به‌دلیل نیاز به تخصیص حافظه‌ی پویا (اگرچه استاندارد توصیه به بهینه‌سازی برای اشیاء کوچک دارد) و بررسی‌های زمان اجرا است. دومین هزینه، پیچیدگی کد ناشی از نیاز به any_cast صریح برای هر بار دسترسی است که می‌تواند خوانایی را کاهش دهد. در پروژه‌های واقعی، مانند Apache Avro، مشاهده شده است که جایگزینی std::any با std::variant در مواقعی که نوع داده‌ها قابل پیش‌بینی است، می‌تواند تا ۵۰٪ زمان تراکنش‌ها را کاهش دهد. بنابراین، قاعده‌ی طلایی این است: اگر می‌توانید لیست انواع ممکن را در زمان کامپایل مشخص کنید، از std::variant استفاده کنید و std::any را برای شرایطی که نوع داده‌ها کاملاً پویا و از پیش ناشناخته هستند، نگه دارید.

کلیدواژه ها : std::any-مدیریت تایپ دلخواه در C++-C++17 any-مزایا و معایب std::any-آموزش std::any-std::any_cast-std::bad_any_cast-std::make_any-std::any has value-مقایسه any و variant-مدیریت نوع پویا در C++-ذخیره هر نوع داده در C++-std::any reset-std::any swap-نکات std::any-بهینه‌سازی std::any-کاربرد std::any