Skip to main content

Boost.Any

boost::any is a container for a single value of any type, decided at runtime. Where Boost.Variant holds one of a fixed, known set of types, any holds one of an open, unknown set — you can store an int today and a std::vector<std::string> tomorrow in the same variable. This is classic type erasure, and it inspired C++17's std::any.

When you genuinely do not know the type

any is for the rare situation where the set of possible types is open-ended or only known by external data — plugin systems, scripting bridges, generic property bags, message buses. If you can enumerate the types up front, a variant is almost always the better tool.

Storing and retrieving

A value goes in by simple assignment. Getting it back requires boost::any_cast, and you must name the exact stored type — there are no implicit conversions.

any_basics.cpp
#include <boost/any.hpp>
#include <string>
#include <iostream>

int main() {
boost::any a = 42; // holds int
a = std::string("hello"); // now holds std::string

// Value form: throws boost::bad_any_cast on type mismatch.
std::string s = boost::any_cast<std::string>(a);
std::cout << s << "\n";

// Pointer form: returns nullptr on mismatch, no exception.
if (int* p = boost::any_cast<int>(&a)) {
std::cout << *p << "\n"; // not reached: a holds a string
}
}
any_cast is exact-match only

boost::any_cast<long>(a) on an any holding an int throws — type erasure remembers the precise typeid, and there is no arithmetic conversion. Cast to the type you stored, then convert.

Inspecting and emptying

#include <boost/any.hpp>
#include <typeinfo>

void inspect(const boost::any& a) {
if (a.empty()) return; // default-constructed or cleared
const std::type_info& t = a.type(); // the stored type's typeid
(void)t;
}

An any constructed with no argument is empty; assigning boost::any() clears it. type() exposes the std::type_info of the stored object, which you can pair with boost::core::demangle for readable diagnostics.

A concrete use: a heterogeneous property bag

property_bag.cpp
#include <boost/any.hpp>
#include <map>
#include <string>

class Properties {
std::map<std::string, boost::any> data_;
public:
template <class T>
void set(const std::string& key, T value) { data_[key] = std::move(value); }

template <class T>
T get(const std::string& key) const {
return boost::any_cast<T>(data_.at(key)); // throws if wrong type
}
};

int main() {
Properties p;
p.set("width", 1920);
p.set("title", std::string("main window"));
int w = p.get<int>("width");
(void)w;
}

any versus variant versus virtual functions

These three are the standard answers to "I need to handle values whose type varies", and they sit at different points on the openness/safety spectrum.

ApproachType setCheckingAccess costBest for
variantfixed, knowncompile-time (visitor)cheap, in-placeenumerable alternatives
virtual interfaceopen, shares behaviourcompile-time on interfacevtable dispatchpolymorphic behaviour
anyopen, unrelated typesruntime (any_cast)type check + maybe heaptruly unknown types
Reach for variant first

Most "I need a flexible value" problems actually have a small, known set of types — use a variant and let the compiler check exhaustiveness. Choose any only when the types are genuinely open and share no common interface, because all the safety moves to runtime.

Boost.Any versus std::any

C++17 standardised the concept as std::any, with essentially the same interface.

Aspectboost::anystd::any (C++17)
Header<boost/any.hpp><any>
Castboost::any_cast<T>std::any_cast<T>
Bad castboost::bad_any_caststd::bad_any_cast
Emptinessa.empty()a.has_value()
In-place buildboost::any(...)std::make_any<T>, emplace
Small-object optimisationimplementation-dependenttypically yes
Which to use

On C++17+, prefer std::any — it is standard, needs no dependency, and commonly stores small types without heap allocation. Use boost::any for pre-C++17 toolchains or code already inside the Boost dependency graph. See Boost and the C++ Standard.

See also