Get rid of unions and some more advantages of std::variant.
Let’s go back to C++17. It is already a while out there and a feature I really like is std::variant
.
It is handy in a lot of places. In all places you may have used unions before. Having an Interface which accepts a std::variant
which it does not use itself, but passes it further makes the interface slimmer and easier.
You could have done that with templates, but using std::variant
is much more simple.
Let’s look at some code.
#include <string>
#include <variant>
#include <iostream>
using namespace std::literals;
void funcb(std::variant<int, std::string>& data){
if(auto pval = std::get_if<std::string>(&data)){
std::cout << "a string, how nice: " << pval << std::endl;
}
else{
std::cout << "not a string, something else" << std::endl;
}
}
void a(std::variant<int, std::string>& data){
std::cout << "size is " << sizeof(data) << std::endl;
funcb(data);
}
int main(){
std::variant<int, std::string> s = "AString"s;
std::variant<int, std::string> z = 3208;
a(s);
a(z);
return 0;
}
Ok, so we are able to pass things without bothering. I mean in this case it has been easy, we have a string and an integer. So is there another way than these std::get_if
? Indeed. Use std::visit
.
std::visit
in combination with lambdas is really great. You are using templates without a single template parameter. It is so nice, elegant and not too hard.
#include <string>
#include <variant>
#include <iostream>
using namespace std::literals;
void a(std::variant<int, std::string>& data){
std::cout << "size is " << sizeof(data) << std::endl;
std::visit([](auto&& arg){
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int>){
std::cout << "int " << arg << '\n';
}else if constexpr (std::is_same_v<T, std::string>){
std::cout << "string " << arg << '\n';
}
}, data);
}
int main(){
std::variant<int, std::string> s = "AString"s;
std::variant<int, std::string> z = 3208;
a(s);
a(z);
return 0;
}
The lambda in the std::visit
is using constexpr
. This will reduce the generated functions to a minimum. The lamba here act like a template and we do a specialization there so it handles all types correctly.
I found this pretty useful also for some kind of serialization. So you have it all in one place.