if (const auto sPtr (std::get_if<std::string>(&myVariant)); sPtr) {
/* use sPtr */
} else if (const auto iPtr (std::get_if<int>(&myVariant)); iPtr) {
/* use iPtr */
} if (const auto sPtr (std::get_if<std::string>(&myVariant)); sPtr) {
/* use sPtr */
} else if (const auto iPtr (std::get_if<int>(&myVariant)); iPtr) {
/* use iPtr */
} if (std::string* s = std::get_if<std::string>(&myVariant)) {
// Use s
}
else if (int* i = std::get_if<std::string>(&myVariant)) {
// Use i
}
else {
throw std::logic_error("Unexpected type in variant");
}
The hardcore modern C++ gang will vigorously complain that using this kind of chained if will - horrors! - yield a runtime error instead of a compile time error if you have forgotten one of the types that the variant can hold. I have some sympathy for that point of view, but in practice the small likelihood of that bug happening and the small extra difficulty of finding it at runtime is completely overshadowed by the extra complexity of std::visit.I don't agree with GP's claim that chained ifs are likely to be slower than std::visit. If anything, it seems like they'd give the compiler less work to do to optimise well than the layers of funtion calls involved in std::visit, especially since std::visit is ultimately going to expand to chained if statements anyway.
(A digression that's maybe dangerous to bring up: You've made an odd choice out of the many initialisation syntaxes to use. Many in the hardcore modern C++ gang would advise always using auto and brace initialisation, with no equals, even for really simple variable definitions e.g. auto i{int(3)};. Personally I find that obtuse and would write that as int i = 3, at least for simple things (raw pointers like in the example above fall into that category for me). Direct initialisation with parentheses isn't normally advocated by either old-timers or modern C++ fans, in part because of the most vexing parse - did you mean to use braces?)
Re: compile time vs runtime errors, it is a valid point. In Scala (which I use in my day job) I will generally question any use of `case _ =>` in a pattern match because of this, particularly because you don't get the nice compiler error when someone (for example) adds a new type to a sealed trait hierarchy without making sure all business logic that touches that type handles the new case correctly. I guess in C++ it feels painful for a non-expert like myself to get those types of compile time guarantees while functional languages like Scala (for example) make it easy.
I mean, I can grok it, but I’d never write it. I’d fall back to the ‘write methods to encapsulate the behaviour’ approach instead, and I think my co-workers would thank me for it.