5 ms·
Yes, you read about std::variant on a blog and think that it is a sum type. Then you try it out and realize that it's a thin (type-safe) wrapper over tagged uni
by fgkhax 2y ago
Yes, you read about std::variant on a blog and think that it is a sum type. Then you try it out and realize that it's a thin (type-safe) wrapper over tagged unions that is at least three times slower and has about 5 unreadable alternatives that replace simple switch statements.
Then you find out that members of a "variant" are not really variant members but just the individual types that can be assigned to a union. For example, assigning to a non-const reference does not work (and obviously cannot work once you realize that std::variant is just syntax sugar over a tagged union).
Most of these new additions since C++11 are just leaky abstractions and wrappers.
- galkk 2y agoOhh, and to make the use of a variant to look like pattern match over type you need to copy paste some template magic. https://schneide.blog/2018/01/11/c17-the-two-line-visitor-explained/ https://schneide.blog/2018/01/11/c17-the-two-line-visitor-ex... variants are a such disappointment at every step of trying to use them
- nly 2y agoA few code snippets of what you see as weaknesses of std::variant may be appropriate, as I couldn't figure out your complaint. Assigning to a variant taken by non-const& works fine for me. I personally would have liked to see recursive variant types and multi-visitation (as supported by boost::variant).
- amluto 2y agoI think the comment means: std::variant<int&, etc> does not work well.
- nly 2y agoJust use std::variant<int*, ...> References in C++ are just sugary pointers.
- robmccoll 2y agoReferences have one important property over pointers. They cannot be null.
- tstack 2y agoThey most certainly can be null as can “this”.
- cma 2y agoconst ref lifetime extension is important to, or operator overloading wouldn't be workable.
- gpderetta 2y agoReference_wrapper then.
- LowLevelMahn 2y agothey easily can :) void test(int& y){} int main() { int* x = nullptr; test(*x); }
- josefx 2y agoThere is a difference between an API promissing that a value wont be null and a buggy program setting a null where it should not. A reference is only null if someone fucked up. As a programmer you can usually rely on a reference not being null and you couldn't do anything about it if it was anyway within the constraints of the language.
- tlhand 2y agostd::variant is not a true algebraic data type, since the individual element constructors do not construct the variant type automatically. Compare to OCaml, written in a verbose and unidiomatic way that is similar to C++: # type foo = Int of { n : int } | Float of { f : float };; type foo = Int of { n : int; } | Float of { f : float; } # Int { n = 10 };; - : foo = Int {n = 10} # let r = ref (Int { n = 10 });; val r : foo ref = {contents = Int {n = 10}} Notice that the constructor Int { n = 10 } automatically produces a foo type and assigning to a mutable ref works. The same in C++, using assignment to a pointer to avoid the lvalue ref error that is irrelevant to this discussion: #include <variant> struct myint { int n; myint(int n) : n(n) {} }; struct myfloat { float f; myfloat(float f) : f(f) {} }; using foo = std::variant<myint, myfloat>; int main() { const foo& x = myint{10}; // works foo *z = new myint{10}; // error: cannot convert ‘myint*’ to ‘foo* } As stated above, this obviously cannot work since C++ has no way of specifying a myint constructor that -- like in OCaml -- automatically produces the variant type foo. C++ would need true algebraic data types with compiler support (that would hopefully be as fast as switch statements). To be useful, they would need a nice syntax and not some hypothetical abomination like: using foo = std::variant<myint, myfloat> where struct myint of foo { ... };
- gpderetta 2y ago> and obviously cannot work once you realize that std::variant is just syntax sugar over a tagged union It would be easy to make it work, there isn't necessarily a strict relation between the template parameter and the actual stored object. Not having reference variant members was a conscious decision, same as optional<T&>. Hopefully this will be fixed in the future.