Right, I'm not trying to argue that std::variant is better than native language support. By definition, a language construct will always be easier to write and read.
All I'm saying is that the current state of std::variant makes it okay enough to use type safe discriminated unions.
Visit + overload is not that far away from pattern matching in terms of readability, clang does warn on non exhaustive switch cases, etc.
You did ask more generally:
> Does that really need to be part of the language though, or as long as you can code it, or have it in the standard library, it's fine?
And my answer is, yes. I don't consider `std::variant` a proper replacement, more like a crutch that may even be worse than not having anything at all, because its existence can be used as an argument against introducing language-level sum types in the future.
C++ is going to have pattern matching "any year now", and it's going to make `std::variant` more ergonomic to use, but on the other hand any pattern matching feature will have to make design compromises in order to support `std::variant` and other mutually-incompatible variant-like library types of which C++ has a bunch of (pointers, unions, `std::optional`, `std::any`, `std::expected`, did I miss any?) Add to that all the zillions of third-party variant-like types (including boost::variant) that exist in the wild because the code base predates C++17 and/or doesn't want to use C++17 features for whatever reason. All this complexity could've been avoided had the language just supported real sum types from the start. Or at least from C++11 up or whatever.
As a sibling commenter noted, algebraic data types and pattern matching with compile-time exhaustiveness checking go hand in hand; I meant to mention the latter in my original comment, but left it out because I consider the latter almost implied by the former.