3 ms·
That's a bit hyperbolic. Sure, it's not exactly ergonomic, but that doesn't mean I can't use it. One thing that bugs me is that there is still no overload helpe
by spacechild1 1y ago
That's a bit hyperbolic. Sure, it's not exactly ergonomic, but that doesn't mean I can't use it. One thing that bugs me is that there is still no overload helper in the standard:
// helper type for the visitor
template<class... Ts>
struct overloads : Ts... { using Ts::operator()...; };
Of course, having true pattern matching would be much nicer. At least there's a proposal: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2688r3.html https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p26...
- forrestthewoods 1y agoI will boldly state that std::variant makes all code worse and it is always better to not use it. I love sum types in Rust. They’re great. This stuff exists solely to add ergonomics. If it’s not ergonomic it’s just making your code worse! std::variant is fundamentally broken because it uses types as its discriminant. Want a variant with two ints that represent two things? Fuck you, you can’t. Rust enums of course can do this. std::visit is an abomination. As is the template overloaded bullshit you have to copy paste into projects. And of course the error messages when you get when it’s wrong are atrocious even by C++ standards. No. std::variant is awful and you should simply never use it. This could change in 2040 when you can use C++32. But for now just avoid it.
- Maxatar 1y ago>Want a variant with two ints that represent two things? Fuck you, you can’t. This is false, I also find that in general you have a tendency to make false claims about C++ in most of your posts about it. I would suggest you check out a resource like https://en.cppreference.com/ https://en.cppreference.com/ just as a sanity check before you make claims about the language in the future, and also because it's a very good resource for learning the ins and outs of the language. As for your claim, std::variant supports index based discrimination similar to std::tuple, so you can absolutely have a std::variant<int, int>, and access the second int along the lines of: auto foo = std::variant<int, int>(); std::get<1>(foo) = 123; std::cout << std::get<1>(foo); This is all documented with examples: https://en.cppreference.com/w/cpp/utility/variant/get.html https://en.cppreference.com/w/cpp/utility/variant/get.html
- mk12 1y agoWould you ever really use that? That just shows how bad it is, IMO. Any time I want a sum type I want names, not hardcoded integers.
- loeg 1y agoI wouldn't use it (in any language), but the claim was that it is impossible. It isn't.
- Maxatar 1y agoI treat std::variant the same way I treat std::tuple, which is that I use them internally/privately and don't expose them as part of a public API. If I want to expose a std::variant publicly then I take the effort to emulate Rust, which I think everyone agrees has an incredibly useful and elegant enum type so it looks like this: int main() { auto s1 = ConnectionState::Disconnected(); auto s2 = ConnectionState::Connecting(3); auto s3 = ConnectionState::Connected("192.168.1.5", 8080); for (const auto& state : {s1, s2, s3}) { state.visit( [](Disconnected) { std::cout << "Disconnected\n"; }, [](int retries) { std::cout << "Connecting (" << retries << " retries)\n"; }, [](const IpAddress& ip) { std::cout << "Connected to " << ip.host << ":" << ip.port << "\n"; }); } } To implement that I currently do need to write out boilerplate like below, but with C++26 I will be able to use the upcoming reflection feature to automatically implement the bulk of this code by reflecting on the std::variant directly: class ConnectionState : private std::variant<std::monostate, int, IpAddress> { public: static auto Disconnected() { return ConnectionState(std::monostate{}); } static auto Connecting(int retries) { return ConnectionState(retries); } static auto Connected(std::string host, uint16_t port) { return ConnectionState(IpAddress{std::move(host), port}); } template <typename... Fs> decltype(auto) visit(Fs&&... fs) const { auto visitor = Overload{std::forward<Fs>(fs)...}; return std::visit(visitor, *this); } private: using std::variant<std::monostate, int, IpAddress>::variant; }; using Disconnected = std::monostate; ...
- forrestthewoods 1y ago
- spacechild1 1y ago> I will boldly state that std::variant makes all code worse and it is always better to not use it. And I will boldly state that your comment is again completely hyperbolic. > std::variant is fundamentally broken because it uses types as its discriminant. In my experience, the typical use case for std::variant is static polymorphism. For this purpose it works just fine because the type is the discriminator. Another popular use case is tagged unions for non-POD types. In this case, you probably access the active member with std::get. This even works with duplicate types, if you access by index. Would proper sum types and pattern matching be nice? Of course! But does this mean that std::variant is fundamentally broken? I don't think so.