Hacker News new | ask | show | jobs
by nly 688 days ago
A 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).

2 comments

std::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 { ... };
I think the comment means:

    std::variant<int&, etc>
does not work well.
Just use

    std::variant<int*, ...>
References in C++ are just sugary pointers.
References have one important property over pointers. They cannot be null.
Reference_wrapper then.
they easily can :)

void test(int& y){}

int main() { int* x = nullptr; test(*x); }

There 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.
In the same way, an `enum class` variable's value being outside of the set defined in the `enum class` is also a fuckup.
And you can also open /proc/self/mem in a Rust program and overwrite whatever you want, including pointers. So?
One of those cases happens accidentally all the time (in more complex variants than the motivating example you responded to), the other never happens except on purpose. It's like complaining guard rails are pointless because people being launched with catapults might still fly over them and plunge to their deaths.
const ref lifetime extension is important to, or operator overloading wouldn't be workable.
They most certainly can be null as can “this”.
Only after dereferencing a null pointer, which would be the actual problem, not the fact that some reference or this is null.
You cannot have a null reference unless you invoke undefined behavior first.