Skip to content

Variant (boost::variant)

Frederik Rokkjær edited this page Oct 2, 2020 · 6 revisions

Exercise 1: Defining and using a boost::variant

Define a boost::variant with a number of different types. The only requirement is that one of them must be user defined. The task is to write the contents of the boost::variant variable to std::cout regardlessly of which type is the current one in use. Implementation wise boost::variant is streamable, if and only if all types it has been parameterized with are streamables.

Exercise 1.1: Type not streamable...

To start with our user defined type is not streamable. In other words, writing something like std::cout << v << std::endl; will not work, assuming that v is a boost::variant. Therefore inspect the boost::variant API and determine which methods to use in order to handle the above.


#include <boost/variant.hpp>
#include <string>
#include <iostream>

int main()
{
    boost::variant<int, std::string, double> v;
    v = 255;
    std::cout << boost::get<int>(v) << std::endl;
    v = "Hello, World!";
    std::cout << boost::get<std::string>(v) << std::endl;
    v = 3.1415;
    std::cout << boost::get<double>(v) << std::endl;
    return 0;
}

The output is:

255
Hello, World!
3.1415

Exercise 1.2: Fix the streamable issue

To complete this exercise make your type streamable by implementing std::ostream& operator <<(std::ostream&, const <your type>&). Now test the code std::cout << v << std::endl; that did not work before


To implement the overload, we first need to make a template, since we don't want to make an overload for every variant type.

#include <boost/variant.hpp>
#include <iostream>
#include <string>

template <typename T>
std::ostream &operator<<(std::ostream &os, const boost::variant<T> &var)
{
  os << boost::get<T>(var);
  return os;
}

int main()
{
  boost::variant<int, std::string, double> v;
  v = 255;
  std::cout << v << std::endl;
  v = "Hello, World!";
  std::cout << v << std::endl;
  v = 3.1415;
  std::cout << v << std::endl;
  
  return 0;
}

Output:

255
Hello, World!
3.1415

Exercise 2: Using visitation

As seen in the previous exercise we need to determine which type a given boost::variant actually contains before performing some desired deed, which obviously is not surprising. However it means that I/we as developers would have to write the same test code every time. Fortunately boost::variant supports visitation that alleviates us from performing this task. Stuff to do:

  • Explain visitation
  • Write a functor that has an function operator overloaded for each type in your boost::variant. Remember to inherit properly from boost::static_visitor.
  • In each of these overloads write out the variable’s contents as well as some text such that it is clear from where it came
  • Try to compile your code before all overloads have been completed - What happens and why?

#include <boost/type_index.hpp>
#include <boost/variant.hpp>
#include <iostream>
#include <string>
#include <vector>

class FunctorClass : public boost::static_visitor<>
{
private:
  /* data */
public:
  template <typename T> void operator()(T t) const
  {
    std::cout << boost::typeindex::type_id<T>().pretty_name() << ' ' << t
              << std::endl;
  }
};

int main()
{
  FunctorClass visitor;
  std::vector<boost::variant<int, std::string, double, char>> vec;

  vec.push_back("Hello, World!");
  vec.push_back(420.69);
  vec.push_back(42);
  vec.push_back('F');

  std::for_each(vec.begin(), vec.end(), boost::apply_visitor(visitor));
}

Output:

std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > Hello, World!
double 420.69
int 42
char F