Use Modern C++ std::any in your projects

marcosplusplus

Marcos Oliveira

Posted on June 20, 2024

Use Modern C++ std::any in your projects

Say goodbye to void* once and for all.


std::any is a feature of the C++ standard library that was introduced in C++17.

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:

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
Enter fullscreen mode Exit fullscreen mode

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) 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!

#include <any>
Enter fullscreen mode Exit fullscreen mode

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

#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';
}
Enter fullscreen mode Exit fullscreen mode

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 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:

some_data.reset();
// Or
some_data = {};
Enter fullscreen mode Exit fullscreen mode

โ€” And to check if std::any is empty?

Use has_value():

std::cout << (some_data.has_value() ? "Full!" : "Empty.") << '\n';
Enter fullscreen mode Exit fullscreen mode

The unionless type() with name() can be used to compare types:

std::cout << (some_data.type() == typeid(void)) << '\n'; // 0 to false
std::cout << (some_data.type() == typeid(int)) << '\n'; // 1 to true
Enter fullscreen mode Exit fullscreen mode

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:

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;
}
Enter fullscreen mode Exit fullscreen mode

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

๐Ÿ’– ๐Ÿ’ช ๐Ÿ™… ๐Ÿšฉ
marcosplusplus
Marcos Oliveira

Posted on June 20, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

ยฉ TheLazy.dev

About