Use Modern C++ std::any in your projects
Tags: cpp, cpp17, moderncpp
Published: 2024-06-20 23:16:37

### Say goodbye to `void*` once and for all.

---

`std::any` is a feature of the C++ standard library that was introduced in [C++17](https://terminalroot.com/tags#cppdaily).

This component belongs to the set of type-safe container classes, providing a safe means to store and manipulate values ​​of any type.

It is especially useful when you need to deal with situations where the type of the variable can vary! 😃

Then you say:
> **- Oh man! Good. For these cases I use `void *`.**

Yes, you're really right, but have you seen how the new generation is in relation to *memory safety*???

Not to mention that `void*` is really dangerous!

If you do this, it works:
```cpp
void * some_data; // Bad idea

std::string str = "Hi";
int x = 3;
decltype(x) y = 6;

some_data = &str;
std::cout << *(std::string*)some_data << '\n';

some_data = &x;
std::cout << *(int*)some_data << '\n';

some_data = &y;
std::cout << "Type of y: " << typeid(y).name() << '\n'; // include typeinfo
```

But, the chance of this giving `mer%$a` is great! At the end of using these variables, `some_data` will continue to exist, that is, an indefinite lifetime!

And it is to replace `void*` that `std::any` was created in Modern C++ which, of course, is totally **Safe**!

In other words, it is a *wrapper* that encapsulates your variable to a `shared_ptr`([smart pointers](https://en.cppreference.com/book/intro/smart_pointers)) of life! Yes, and there is even a `std::make_any`!!!

---

## How to use `std::any`
First you need to include its header:
> Logically, it only works from C++17 as was said at the beginning!

```cpp
#include <any>
```

And now the same code that was presented above, but using `std::any`:

```cpp
#include <iostream>
#include <any>

int main(){
 std::any some_data;

 std::string str = "Hi";
 int x = 3;
 auto y = std::make_any<decltype(x)>(6);

 some_data = str;
 std::cout << std::any_cast<std::string>(some_data) << '\n';

 some_data = x;
 std::cout << std::any_cast<int>(some_data) << '\n';

 some_data = y;
 std::cout << "Type of y: " << some_data.type().name() << '\n';
}
```

In the code above we saw that:
+ `std::any some_data;` - Declares the variable;
+ `std::any_cast<T>(some_data)` - Converts to the desired type;
+ `std::make_any<T>` - Another way to create objects;
+ `some_data.type().name()` - Gets the data type without needing `typeinfo`.

And you can use it for absolutely everything: `std::vector`, [Lambda](https://terminalroot.com/10-examples-of-using-lambda-functions-in-cpp/) and all existing data types!

And the guy asks something else:
> **- OK! What if I want to end the lifetime of `std::any` manually?**

Just use the `reset` union structure or even the initialization operator:

```cpp
some_data.reset();
// Or
some_data = {};
```

> **— And to check if `std::any` is empty?**

Use `has_value()`:

```cpp
std::cout << (some_data.has_value() ? "Full!" : "Empty.") << '\n';
```

The unionless `type()` with `name()` can be used to compare types:
```cpp
std::cout << (some_data.type() == typeid(void)) << '\n'; // 0 to false
std::cout << (some_data.type() == typeid(int)) << '\n'; // 1 to true
```
> To use *Boolean* names use: `std::cout << std::boolalpha << (some_data.type() == typeid(int)) << '\n';`.

To throw exceptions you must use `std::bad_any_cast`:
```cpp
try {

 std::any any_str("Hiii");
 auto my_any{ std::make_any<std::string>(any_str.type().name()) };
 std::cout << std::any_cast<std::string>(my_any) << '\n';

}catch (const std::bad_any_cast& e) {
 std::cerr << "Error: " << e.what() << std::endl;
}
```

To check whether everything really complies, never forget to use the flags for your compiler: `-Wall -Wextra -pedantic -g -fsanitize=address`.

---

In addition to being completely **SAFE**, `std::any` is very practical and a great help!

There was a company project that I was developing, which passed a function argument and could be any type, but the function's return was `std::string` concatenated to the name of the object received.

And someone had created a great `switch case` to convert to `std::string`(*bizarre!*), I substituted it to receive the parameter for `std::any` and converted it with `std::any_cast< std::string>` and I solved it in a way: Modern, Safe and Like a Boss! Exactly what `std::any` is!!! 😃

For more information visit: <https://en.cppreference.com/w/cpp/utility/any>