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.
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).
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).
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.
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()
.
#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
.
#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.