Lumiera
0.pre.03
»edit your freedom«
|
Go to the source code of this file.
A typesafe union record to carry embedded values of unrelated type.
This file defines a simple alternative to boost::variant. It pulls in fewer headers, has a shorter code path and is hopefully more readable, but also doesn't deal with alignment issues and is not threadsafe.
Deliberately, the design rules out re-binding of the contained type. Thus, once created, a variant must hold a valid element and always an element of the same type. Beyond that, variant elements are copyable and mutable. Direct access requires knowledge of the embedded type (no switch-on type). Type mismatch is checked at runtime. As a fallback, we provide a visitor scheme for generic access.
The design restrictions were chosen deliberately, since a variant type might promote "probe and switch on type" style programming, which is known to be fragile. Likewise, we do not want to support mutations of the variant type at runtime. Basically, using a variant record is recommended only if either the receiving context has structural knowledge about the type to expect, or when a visitor implementation can supply a sensible handling for all the possible types. As an alternative, you might consider the lib::PolymorphicValue to hold types implementing a common interface.
We use a "double capsule" implementation technique similar to lib::OpaqueHolder. In fact, Variant is almost identical to the latter, just omitting unnecessary flexibility. The outer capsule exposes the public handling interface, while the inner, private capsule is a polymorphic value holder. Since C++ as such does not support polymorphic values, the inner capsule is placed "piggyback" into a char buffer. The actual value is carried within yet another, nested char buffer. Thus, effectively the first "slot" of the storage will hold the VTable pointer, thereby encoding the actual type information – leading to a storage requirement of MAX<TYPES...> plus one "slot" for the VTable. (with "slot" we denote the smallest disposable storage size for the given platform after alignment, typically the size of a size_t).
To support copying and assignment of variant instances, but limit these operations to variants holding the same type, we use a virtual assignment function. In case the concrete type does not support assignment or copy construction, the respective access function is replaced by an implementation raising a runtime error.
handle(TX)
function may shadow other handle(..)
functions from the inherited (generated) Visitor interface. These warnings are besides the point, since not the client uses these functions, but the Variant does, after upcasting to the interface. Make sure you define your specialisations with the override modifier; when done so, it is safe to disable this warning here.Definition in file variant.hpp.
#include "lib/error.hpp"
#include "lib/meta/typelist.hpp"
#include "lib/meta/typelist-util.hpp"
#include "lib/meta/generator.hpp"
#include "lib/meta/virtual-copy-support.hpp"
#include "lib/format-obj.hpp"
#include "lib/util.hpp"
#include <type_traits>
#include <cstddef>
#include <utility>
#include <string>
Namespaces | |
lib | |
Implementation namespace for support and library code. | |