3. Реализуем функцию, которая утверждает, что может вывести на экран любые данные. Обещание заключается вот в чем: она выводит любые данные, предоставленные как аргумент в виде переменной std::any
void print_anything(const std::any &a)
{
4. Первое, что нужно сделать, — проверить, содержит ли аргумент
if (!a.has_value()) {
cout << "Nothing.\n";
5. Если он не пуст, то можно попробовать сравнивать его с разными типами до тех пор, пока не получим совпадение. Первым типом послужит тип string
a
к ссылке string
с помощью std::any_cast
и просто вывести его на экран. Из соображений эстетики мы поместим строку в кавычки: } else if (a.type() == typeid(string)) {
cout << "It's a string: "
<< quoted(any_cast
6. Если это не string
int
. При совпадении данного типа можно использовать преобразование any_cast
, чтобы получить реальное значение int
: } else if (a.type() == typeid(int)) {
cout << "It's an integer: "
<< any_cast
7. std::any
string
и int
. В переменную any можно поместить и ассоциативный массив, список или экземпляр любого другого сложного типа данных. Посмотрим, являются ли входные данные списком целых чисел, и если да, то можем вывести его точно так же, как и любой другой список: } else if (a.type() == typeid(int_list)) {
const auto &l (any_cast
cout << "It's a list: ";
copy(begin(l), end(l),
ostream_iterator
cout << '\n';
8. Если не подошел ни один из перечисленных типов, то у нас закончатся догадки. В таком случае просто сдадимся и скажем пользователю, что не знаем, как выводить эти данные на экран:
} else {
cout << "Can't handle this item.\n";
}
}
9. В функции main
any
с помощью {}
или передать ей строку "abc"
или целое число. Поскольку экземпляр типа std::any
может быть создан на основе этих типов неявно, не возникает задержек, связанных с синтаксисом. Мы даже можем создать целый список и передать его в эту функцию:int main()
{
print_anything({});
print_anything("abc"s);
print_anything(123);
print_anything(int_list{1, 2, 3});
10. Если мы будем помещать объекты, копировать которые действительно дорого, в переменную типа any
in_place_type_t{}
представляет собой пустой объект, дающий конструктору типа any достаточно информации о том, что мы собираемся создать. Второй параметр, {1,2,3}
, — просто список инициализации, который будет передан в int_list
, будучи встроенным в переменную типа any
с целью создания объекта. Это способ избежать ненужного копирования или перемещения. print_anything(any(in_place_type_t
}
11. Компиляция и запуск программы дадут следующие результаты, они полностью соответствуют нашим ожиданиям:
$ ./any
Nothing.
It's a string: "abc"
It's an integer: 123
It's a list: 1, 2, 3,
It's a list: 1, 2, 3,
Как это работает
Тип std::any
std::optional
— он поддерживает метод has_value()
, который говорит, содержит ли экземпляр значение. Но, помимо этого, он может содержать optional
.Прежде чем получать доступ к содержимому переменной типа any
Определить тип значения можно с помощью следующего сравнения: x.type() == typeid(T)
true
, то можно использовать преобразование any_cast
, чтобы получить содержимое.