3 ms·
I've also found std::get_if to be halfway decent in terms of readability. You end up with a if/else-if block that looks a bit like an ugly verbose pattern matc
by dbattaglia 6y ago
I've also found std::get_if to be halfway decent in terms of readability. You end up with a if/else-if block that looks a bit like an ugly verbose pattern match:
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 */
}
- quietbritishjim 6y agoAgreed that std::get_if is nice, it avoids redundantly checking then fetching the value compared to using holds_alternative. But there's no need to have that separate clause in the if statement to test the truthiness of pointer, that's already what will happen from the initialisation: 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?)
- dbattaglia 6y agoNice, your example is cleaner than mine for sure. My example was copied from some code I'd written but looking at it again it's more verbose than necessary. 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.
- spacedcowboy 6y agoAs someone who “uses” C++ as “C with classes”, this looks like line noise... 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.