The Boost C++ Libraries

Chapter 23. Boost.Any

Strongly typed languages, such as C++, require that each variable have a specific type that defines what kind of information it can store. Other languages, such as JavaScript, allow developers to store any kind of information in a variable. For example, in JavaScript a single variable can contain a string, then a number, and afterwards a boolean value.

Boost.Any provides the class boost::any which, like JavaScript variables, can store arbitrary types of information.

Example 23.1. Using boost::any
#include <boost/any.hpp>

int main()
{
  boost::any a = 1;
  a = 3.14;
  a = true;
}

To use boost::any, include the header file boost/any.hpp. Objects of type boost::any can then be created to store arbitrary information. In Example 23.1, a stores an int, then a double, then a bool.

Variables of type boost::any are not completely unlimited in what they can store; there are some preconditions, albeit minimal ones. Any value stored in a variable of type boost::any must be copy-constructible. Thus, it is not possible to store a C array, since C arrays aren’t copy-constructible.

To store a string, and not just a pointer to a C string, use std::string (see Example 23.2).

Example 23.2. Storing a string in boost::any
#include <boost/any.hpp>
#include <string>

int main()
{
  boost::any a = std::string{"Boost"};
}

To access the value of boost::any variables, use the cast operator boost::any_cast (see Example 23.3).

Example 23.3. Accessing values with boost::any_cast
#include <boost/any.hpp>
#include <iostream>

int main()
{
  boost::any a = 1;
  std::cout << boost::any_cast<int>(a) << '\n';
  a = 3.14;
  std::cout << boost::any_cast<double>(a) << '\n';
  a = true;
  std::cout << std::boolalpha << boost::any_cast<bool>(a) << '\n';
}

By passing the appropriate type as a template parameter to boost::any_cast, the value of the variable is converted. If an invalid type is specified, an exception of type boost::bad_any_cast will be thrown.

Example 23.4. boost::bad_any_cast in case of an error
#include <boost/any.hpp>
#include <iostream>

int main()
{
  try
  {
    boost::any a = 1;
    std::cout << boost::any_cast<float>(a) << '\n';
  }
  catch (boost::bad_any_cast &e)
  {
    std::cerr << e.what() << '\n';
  }
}

Example 23.4 throws an exception because the template parameter of type float does not match the type int stored in a. The program would also throw an exception if short or long were used as the template parameter.

Because boost::bad_any_cast is derived from std::bad_cast, catch handlers can catch exceptions of this type, too.

To check whether or not a variable of type boost::any contains information, use the member function empty(). To check the type of the stored information, use the member function type().

Example 23.5. Checking type of currently stored value
#include <boost/any.hpp>
#include <typeinfo>
#include <iostream>

int main()
{
  boost::any a = 1;
  if (!a.empty())
  {
    const std::type_info &ti = a.type();
    std::cout << ti.name() << '\n';
  }
}

Example 23.5 uses both empty() and type(). While empty() returns a boolean value, the return value of type() is of type std::type_info, which is defined in the header file typeinfo.

Example 23.6 shows how to obtain a pointer to the value stored in a boost::any variable using boost::any_cast.

Example 23.6. Accessing values through a pointer
#include <boost/any.hpp>
#include <iostream>

int main()
{
  boost::any a = 1;
  int *i = boost::any_cast<int>(&a);
  std::cout << *i << '\n';
}

You simply pass a pointer to a boost::any variable to boost::any_cast; the template parameter remains unchanged.