C++ | Поради
вступ
З розвитком C++ та впровадженням std::any
і std::variant
у C++17 були додані потужні інструменти для обробки гнучкого зберігання типів і типово-безпечних альтернатив. У цьому пості ми розглянемо ці два інструменти, дослідимо їхні відмінності та зрозуміємо, як ефективно їх використовувати.
Що таке std::any
?
std::any
є частиною Стандартної бібліотеки шаблонів (STL) і призначена для зберігання значень будь-якого типу. Вона дозволяє зберігати і отримувати типи під час виконання програми, що робить її дуже гнучким інструментом для ситуацій, коли тип невідомий під час компіляції.
Основні характеристики std::any
:
- Може зберігати значення будь-якого типу.
- Потрібні перевірки типів під час виконання для отримання збереженого значення.
- Гнучка, але менш продуктивна, ніж типово-безпечні альтернативи, такі як
std::variant
.
Як використовувати std::any
:
#include <any>
#include <iostream>
int main() {
std::any value;
// Зберігаємо ціле число
value = 2;
std::cout << "Збережене ціле число: " << std::any_cast<int>(value) << "\n";
// Зберігаємо рядок
value = std::string("Привіт, Світ!");
std::cout << "Збережений рядок: " << std::any_cast<std::string>(value) << "\n";
return 0;
}
Збережене ціле число: 2
Збережений рядок: Привіт, Світ!
У наведеному прикладі std::any
зберігає спочатку ціле число, а потім рядок. Для безпечного отримання значення використовується std::any_cast
. Якщо ви спробуєте отримати значення невідповідного типу, буде викинуто виключення std::bad_any_cast
.
Коли використовувати std::any
:
- Коли потрібно зберігати значення довільних типів.
- Коли типова безпека не є строгим вимогам.
Що таке std::variant
?
std::variant
є типово-безпечною альтернативою об'єднанням, введена в C++17. На відміну від std::any
, std::variant
може зберігати лише одне значення одночасно, але це значення повинно бути одним із попередньо визначених типів.
Основні характеристики std::variant
:
- Типово-безпечний під час компіляції.
- Без накладних витрат на перевірку типів під час виконання.
- Підтримує шаблонне узгодження за допомогою
std::visit
для чистого оброблення різних типів.
Як використовувати std::variant
:
#include <variant>
#include <iostream>
int main() {
std::variant<int, std::string> var;
// Призначаємо ціле число
var = 10;
std::cout << "Ціле число в variant: " << std::get<int>(var) << "\n";
// Призначаємо рядок
var = "Привіт, Variant!";
std::cout << "Рядок в variant: " << std::get<std::string>(var) << "\n";
return 0;
}
Ціле число в variant: 10
Рядок в variant: Привіт, Variant!
Шаблонне узгодження з std::variant
:
Однією з найпотужніших функцій std::variant
є шаблонне узгодження з використанням std::visit
. Це дозволяє обробляти кожен можливий тип чітко:
#include <variant>
#include <iostream>
int main() {
std::variant<int, std::string> var = "Шаблонне узгодження";
std::visit([](auto&& arg) {
std::cout << "Значення: " << arg << "\n";
}, var);
return 0;
}
Тут std::visit
автоматично визначає тип, який зараз зберігається у variant
, і виконує відповідну логіку.
Коли використовувати std::variant
:
- Коли потрібно зберігати одне значення з попередньо визначеного набору типів.
- Коли потрібна типова безпека і бажано уникати помилок під час виконання.
Основні відмінності між std::any
та std::variant
Практичні випадки використання
Коли вибрати std::any
:
- Реалізація фреймворків для логування, що повинні обробляти довільні типи.
- Загальні контейнери, що зберігають гетерогенні дані.
Коли вибрати std::variant
:
- Моделювання переходів станів у скінчених автоматах.
- Обробка тегованих об'єднань з типово-безпечними способами.
Висновок
Обидва інструменти std::any
та std::variant
є потужними засобами, введеними в C++17, кожен з яких має свої переваги. Використовуйте std::any
для гнучкості, коли типи невідомі під час компіляції.
Використовуйте `` для безпеки типів під час компіляції та кращої продуктивності. Розуміння їхніх відмінностей та випадків використання дозволяє писати більш надійний та підтримуваний код на C++.
Перекладено з: Exploring std::any and std::variant in Modern C++