Skip to content

Improving the variant class

July 24, 2013

Now that alignment support has been implemented in GCC, I can improve the Variant class. At the same time I will discuss a few other improvements that I have made.

Proper alignment support

The main improvement to make is to correctly implement alignment, now that proper alignment support has been implemented in GCC.

The old code looked like the following

union
{
  //max of size + alignof for each of Types...
  char m_storage[m_size]; 
  //the type with the max alignment
  typename max<Alignof, First, Types...>::type m_align;
};

We can now use std::aligned_storage, which looks like this

typename
  std::aligned_storage<m_size, 
    max<Alignof, First, Types...>::value
  >::type
  m_storage;

There are a few differences in the rest of the code. In the original code, m_storage was an array, but now it is a single POD object, so anywhere that we used m_storage, we now need to use &m_storage.

A visitor functor

Since the function apply_visitor is templated, we can’t pass its address to std::bind if we want to create a functor that visits a Variant object. So we add another class visitor_applier that has a templated operator() which visits the Variant passed as argument. Its definition isn’t very interesting, but it has a good use of decltype, so I’ll post it here anyway. It does show that unfortunately sometimes the only way to do this is to duplicate code.

struct visitor_applier
{
  template <typename Visitor, typename Visitable, typename... Args>
  auto
  operator()(Visitor&& visitor, Visitable&& visitable, Args&&... args)
  -> decltype
    (
      apply_visitor
      (
        std::forward<Visitor>(visitor),
        std::forward<Visitable>(visitable),
        std::forward<Args>(args)...
      )
    )
  {
    return apply_visitor
    (
      std::forward<Visitor>(visitor),
      std::forward<Visitable>(visitable),
      std::forward<Args>(args)...
    );
  }
};

Equality of objects

It is sometimes useful to check if two Variant objects are equal. I have added an operator==, which is only true when the two objects are the same Variant, have the same type, and their contained objects’ operator== returns true;

Note that the contained objects only need to have an operator== if you call the Variant’s operator==. So if you don’t want your objects to be comparable, then just don’t call operator== on the Variant.

Querying a Variant’s type

To query whether a Variant holds an object of a specific type, I have added the function variant_is_type. Its definition is trivial

template <typename T, typename V>
bool
variant_is_type(const V& v)
{
  return get<T>(&v) != nullptr;
}
Advertisements
Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: