Book Image

Boost C++ Application Development Cookbook - Second Edition

By : Anton Polukhin Alekseevic
Book Image

Boost C++ Application Development Cookbook - Second Edition

By: Anton Polukhin Alekseevic

Overview of this book

If you want to take advantage of the real power of Boost and C++ and avoid the confusion about which library to use in which situation, then this book is for you. Beginning with the basics of Boost C++, you will move on to learn how the Boost libraries simplify application development. You will learn to convert data such as string to numbers, numbers to string, numbers to numbers and more. Managing resources will become a piece of cake. You’ll see what kind of work can be done at compile time and what Boost containers can do. You will learn everything for the development of high quality fast and portable applications. Write a program once and then you can use it on Linux, Windows, MacOS, Android operating systems. From manipulating images to graphs, directories, timers, files, networking – everyone will find an interesting topic. Be sure that knowledge from this book won’t get outdated, as more and more Boost libraries become part of the C++ Standard.
Table of Contents (19 chapters)
Title Page
Credits
About the Author
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface

Storing multiple chosen types in a container/variable


C++03 unions can only hold extremely simple types called Plain Old Data (POD). For example in C++03, you cannot store std::string or std::vector in a union.

Are you aware of the concept of unrestricted unions in C++11? Let me tell you about it briefly. C++11 relaxes requirements for unions, but you have to manage the construction and destruction of non POD types by yourself. You have to call in-place construction/destruction and remember what type is stored in a union. A huge amount of work, isn't it?

Can we have an unrestricted union like variable in C++03 that manages the object lifetime and remembers the type it has?

Getting ready

We'll be working with the header-only library, which is simple to use. Basic knowledge of C++ is all you need for this recipe.

How to do it...

Let me introduce the Boost.Variant library to you.

  1. The Boost.Variant library can store any of the types specified at compile time. It also manages in-place construction/destruction and even does not even require the C++11 standard:
#include <boost/variant.hpp>
#include <iostream>
#include <vector>
#include <string>

int main() {
    typedef boost::variant<int, const char*, std::string> my_var_t;
    std::vector<my_var_t> some_values;
    some_values.push_back(10);
    some_values.push_back("Hello there!");
    some_values.push_back(std::string("Wow!"));

    std::string& s = boost::get<std::string>(some_values.back());
    s += " That is great!\n";
    std::cout << s;
} 

Great, isn't it?

  1. Boost.Variant has no empty state, but has an empty() function which is useless and always returns false. If you need to represent an empty state, just add some simple type at the first position of the types supported by the Boost.Variant library. When Boost.Variant contains that type, interpret it as an empty state. Here is an example in which we will use a boost::blank type to represent an empty state:
void example1() {
    // Default constructor constructs an instance of boost::blank.
    boost::variant<
        boost::blank, int, const char*, std::string
    > var;

    // 'which()' method returns an index of a type
    // currently held by variant.
    assert(var.which() == 0); // boost::blank

    var = "Hello, dear reader";
    assert(var.which() != 0);
}
  1. You can get a value from a variant using two approaches:
void example2() {
    boost::variant<int, std::string> variable(0);

    // Following method may throw a boost::bad_get
    // exception if actual value in variable is not an int.
    int s1 = boost::get<int>(variable);

    // If actual value in variable is not an int will return NULL.
    int* s2 = boost::get<int>(&variable);
}

How it works...

The boost::variant class holds an array of bytes and stores values in that array. The size of the array is determined at compile time by applying sizeof() and functions to get alignment to each of the template types. On assignment, or construction of boost::variant, the previous values are in-place destructed and new values are constructed on top of the byte array, using the placement new.

There's more...

The Boost.Variant variables usually do not dynamically allocate memory, and they do not require RTTI to be enabled. Boost.Variant is extremely fast and used widely by other Boost libraries. To achieve maximum performance, make sure that there is a simple type in the list of supported types at the first position. boost::variant takes advantage of C++11 rvalue references if they are available on your compiler.

Boost.Variant is part of the C++17 standard. std::variant differs slightly from theboost::variant:

  • std::variant is declared in the <variant> header file rather than in <boost.variant.hpp>
  • std::variant never ever allocates memory
  • std::variant is usable with constexpr
  • Instead of writing boost::get<int>(&variable), you have to write std::get_if<int>(&variable) for std::variant
  • std::variant can not recursively hold itself and misses some other advanced techniques
  • std::variant can in-place construct objects
  • std::variant has index() instead of which()

See also