6

Suppose I have a Shape base class and Circle, Line, and Point derived classes. I have two functions.

std::variant<Circle, Line, Point> process(const Shape &s);
Shape process(const Shape& s);

I can pass in any of my derived classes and return a Shape object in the second function, a variant is just a union that can hold any of my derived class variables at any given time.

Now with std::variant I can also employ a visitor where I can process some function depending on what type my variant is currently holding (I could just create a function object and pass it std::transform and apply it to each of my objects). However, I can just make that function virtual in my base class and have each derived class implement it.

So, is variant just a convenience?

YSC
  • 38,212
  • 9
  • 96
  • 149
Mutating Algorithm
  • 2,604
  • 2
  • 29
  • 66
  • 20
    You seem to be under the impression that `std::variant`'s template arguments must share a common base. You can store unrelated types in an `std::variant`. – François Andrieux Sep 12 '18 at 13:55
  • 1
    imho too broad, though the most obvious is that you can put any types into a variant, while you cannot use a `Circle` and a `Rectangle` polymorphically, unless they both inherit `Shape`, thats a small but big difference – 463035818_is_not_an_ai Sep 12 '18 at 13:55
  • 3
    eg `std::variant`, no chance to get anywhere close to that via inheritance – 463035818_is_not_an_ai Sep 12 '18 at 13:57
  • 2
    FWIW: `Shape process(const Shape& s)` isn't the same as `std::variant process(const Shape &s)` as the former [slices the object](https://stackoverflow.com/questions/274626/what-is-object-slicing). You need to return by reference/smart pointer/pointer. – NathanOliver Sep 12 '18 at 14:00
  • @user463035818 "no chance": You could define wrapper classes around with common base class. Close to? I'd say so - maybe.... Ugly? Sure... – Aconcagua Sep 12 '18 at 14:01
  • @Aconcagua But then you wouldn't have a `std::variant` anymore. – NathanOliver Sep 12 '18 at 14:02
  • 3
    Nice comparison is here: [Inheritance vs `std::variant`](http://cpptruths.blogspot.com/2018/02/inheritance-vs-stdvariant-based.html) – Daniel Langr Sep 12 '18 at 14:03
  • @Aconcagua yeah i was expecting someone to disagree. Replace "no chance to get anywhere close to" as "it would be so tedious and not nice that you wouldnt usually consider it as an option" and I guess we can agree ;) – 463035818_is_not_an_ai Sep 12 '18 at 14:04
  • @user463035818 Sure... Hm, and I must admit I did not consider aesthetics being a potential measure for distance - with that one, it would get quite large... – Aconcagua Sep 12 '18 at 14:14

2 Answers2

10

So, is variant just a convenience?

No, they are different concepts. Main difference that on one side std::variant can work with unrelated types including builtins like int which is not possible with virtual functions directly. On another side std::variant must know types it is working with at compile time. For example it is possible to add a type with virtual function(s) by just linking additional object module without recompiling rest of the code or loading a shared library dynamically to existing application (you do not even have to restart the app) while with std::variant you must recompile code dealing with types std::variant contains.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Slava
  • 43,454
  • 1
  • 47
  • 90
3

However, I can just make that function virtual in my base class and have each derived class implement it.

Yes.... if all the elements in the variant share a common Base (which Slava already mentioned).

Another big difference is that, with a variant, there's not necessarily any dynamic polymorphism happening at all (no RTTI needed) during visitation.

In conjunction with std::visit, there are a lot of tricks under the hood to make sure that there's (basically) zero runtime overhead in calling the appropriate function for a given std::variant. Although there could be non-trivial additional compile time and memory usage because it does this by creating a big matrix of function pointers (See this excellent blog post from Michael Park about it)

AndyG
  • 39,700
  • 8
  • 109
  • 143