4

I understand that boost::variant is implemented something like so

template <typename... Vs>
struct variant {
    std::aligned_union<Vs...>::type buffer;
    ....
};

How can we make an operator<< for a struct like this that prints the casts the type stored in the buffer and passes that to operator<< for cout? For this we would need to know the type of the element stored in the buffer right? Is there a way to know this?

Also I am looking for an explanation of such an implementation, if one exists. Not just that it exists and how I can use it.

Barry
  • 286,269
  • 29
  • 621
  • 977
Curious
  • 20,870
  • 8
  • 61
  • 146

1 Answers1

5

Boost has an apply_visitor function, that takes a generic function object and passes the type of the variant into it. So implementing operator<< is as straightforward as:

template <class... Ts>
std::ostream& operator<<(std::ostream& os, boost::variant<Ts...> const& var) {
    return boost::apply_visitor(ostream_visitor{os}, var);
}

with:

struct ostream_visitor : boost::static_visitor<std::ostream&>
{
    std::ostream& os;

    template <class T>
    std::ostream& operator()(T const& val) {
        return os << val;
    }
};

Or simply:

template <class... Ts>
std::ostream& operator<<(std::ostream& os, boost::variant<Ts...> const& var) {
    return boost::apply_visitor([&os](const auto& val) -> std::ostream& {
        return os << val;
    }, var);
}

You can see some other examples in the tutorial.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • Thank you for your answer! Could you explain it a bit more please. I have not really understood what is going on... How does the `ostream_visitor` know what the type of the variant it? The `T` in the function seems to just resolve to the type `boost::variant`. – Curious Mar 25 '16 at 16:07
  • @Curious No, it definitely doesn't. Read the tutorial, it's all pretty well explained in there. – Barry Mar 25 '16 at 16:10
  • Thank you. I upvoted your answer. I will read it. But in the functor you are just passing in the variant type right? How does boost know what the type of the object is that is in the variable? I meant to ask things more on the lines of how boost implemented this – Curious Mar 25 '16 at 16:10
  • That's why I added in the last sentence in my question. Sorry if I was not clear that I wanted an explanation of the implementation. – Curious Mar 25 '16 at 16:15
  • @Curious The `variant` knows what type it is holding onto. It just calls the function you pass in with its storage appropriately cast. That's why it has to be a generic function object. – Barry Mar 25 '16 at 16:20
  • But how does variant know that? I cannot seem to understand the implementation – Curious Mar 25 '16 at 16:40
  • 4
    @Curious I'm really not going to explain "how does `variant` work" in a comment. You can look at the boost implementation and there are numerous blog posts about how to implement a variant type in C++. – Barry Mar 25 '16 at 16:44