4.6.0
Freundlich's C++ toolkit
Loading...
Searching...
No Matches
fcppt.variant

Description

A class that can hold any object from a fixed set of types.

Motivation

A variant is a type that can hold objects of a fixed set of types, which is sometimes also called a sum type. The closest language feature in C++ are unions, which are very low-level and dangerous to use:

union int_or_float
{
int i;
float f;
};
int_or_float var; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
// Undefined behaviour because the union doesn't store anything
// std::cout << var.i << '\n';
// Ok, but doesn't track that the type is int
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
var.i = 1;
// Undefined behaviour because the union stores an int
// std::cout << var.f << '\n';
auto const print([](int_or_float) {
// how do we know which type of object is stored?
});
print(var);

fcppt::variant fixes the aforementioned problems in the following way:

Consider a variant of an int and a string, for which we provide a print function:

auto const print([](string_or_int const &_v) {
_v,
[](std::string const &_str) { std::cout << "We have a string " << _str << '\n'; },
[](int const _i) { std::cout << "We have an int " << _i << '\n'; });
});
string_or_int const var(std::string("Hello World"));
print(var);

Notice that we do not query which type the variant holds. Instead, we make use of fcppt::variant::match and write out all cases explicitly.

Visitation

A more general way to access variants is called visitation, which is similar to pattern matching. A visitor is a struct or class that uses an overloaded operator() to distinguish between the possible types of a variant.

Suppose we want to define a visitor that does something different for all integral types. The easiest way this can be done is by using std::enable_if.

struct print_visitor
{
template <typename T>
void operator()(T const &_value) const
requires(!std::is_integral_v<T>)
{
std::cout << "Not integral: " << _value << '\n';
}
template <typename T>
void operator()(T const _value) const
requires(std::is_integral_v<T>)
{
std::cout << "Integral: " << _value << '\n';
}
};

The following code shows how such a visitor is called:

// Prints "Not integral: Hello World".
fcppt::variant::apply(print_visitor(), string_or_int(std::string("Hello World")));
// Prints "Integral: 42".
fcppt::variant::apply(print_visitor(), string_or_int(1));

Here is a small example for defining a binary visitor:

string_or_int const v(std::string("Hello World"));
string_or_int const u(1);
// Does a binary visitation.
// Prints "Hello World" 1.
[](auto const &_val1, auto const &_val2) { std::cout << _val1 << ' ' << _val2 << '\n'; },
v,
u);

Non-const visitation, which means that the visited variant can be modified, is also supported.

struct visitor
{
// operator() takes T as non const ref
template <typename T>
void operator()(T &_val) const
{
// reset _val to the default value
_val = T();
}
};
string_or_int v{std::string("Hello World")};
fcppt::variant::apply(visitor(), v);
// only prints a newline because the string contains nothing anymore
std::cout << fcppt::variant::get_unsafe<std::string>(v) << '\n';

Access

Visitation and matching are the most common ways to access a variant. The other ways are:

Design

While the design of fcppt::variant is similar to std::variant, there are some key differences:

Header files

Header file Description
object_fwd.hpp Contains fcppt::variant::object variants's declaration.
object_decl.hpp Contains fcppt::variant::object variant's definition.
object_impl.hpp Contains the definition of fcppt::variant::object variants's member functions.
object.hpp The same as object_impl.hpp.
apply.hpp Contains fcppt::variant::apply .
compare.hpp Contains fcppt::variant::compare .
comparison.hpp Contains operator<, operator== and operator!=.
from_list_fwd.hpp Contains fcppt::variant::from_list.
from_list.hpp Includes fcppt/variant/object_fwd.hpp and defines fcppt::variant::object.
get_unsafe.hpp Contains fcppt::variant::get_unsafe which does the same thing as the fcppt::variant::object::get_unsafe member function.
holds_type.hpp Contains the fcppt::variant::holds_type function to check if a type is held by the variant.
match.hpp Contains fcppt::variant::match.
output.hpp Contains operator<< for output.
to_optional.hpp Contains fcppt::variant::to_optional.
to_optional_ref.hpp Contains fcppt::variant::to_optional_ref.
type_info.hpp Contains fcppt::variant::type_info.

Classes

class  fcppt::variant::object< Types >
 A class that can hold any object from a fixed set of types. More...
 

Typedefs

template<fcppt::mpl::list::object_concept Types>
using fcppt::variant::dynamic_cast_types = fcppt::mpl::list::map<Types, fcppt::mpl::lambda<fcppt::reference>>
 The variant element types used for fcppt::variant::dynamic_cast_.
 
template<fcppt::mpl::list::object_concept Types>
using fcppt::variant::from_list = fcppt::mpl::list::as<fcppt::variant::object, Types>
 Declares a variant using an mpl::list.
 
template<fcppt::variant::object_concept Variant, typename Element >
using fcppt::variant::has_type = fcppt::mpl::list::contains<fcppt::variant::types_of<Variant>, Element>
 Checks if a variant has a specific type.
 
template<typename Container >
using fcppt::variant::partition_result
 The result of fcppt::variant::partition.
 
using fcppt::variant::size_type = std::size_t
 An integer type used to describe a type index.
 
template<fcppt::variant::object_concept Variant>
using fcppt::variant::types_of = typename fcppt::variant::detail::types_of<std::remove_cvref_t<Variant>>::type
 The types of a variant.
 

Functions

template<typename Function , fcppt::variant::object_concept... Variants>
decltype(auto) fcppt::variant::apply (Function const &_function, Variants &&..._variants)
 Applies a function to the elements of several variants.
 
template<typename... Types, typename Compare >
bool fcppt::variant::compare (fcppt::variant::object< Types... > const &_left, fcppt::variant::object< Types... > const &_right, Compare const &_compare)
 Compares two variants using a Compare function.
 
template<typename... Types>
bool fcppt::variant::operator== (fcppt::variant::object< Types... > const &_left, fcppt::variant::object< Types... > const &_right)
 Compares two variants for equality.
 
template<typename... Types>
bool fcppt::variant::operator!= (fcppt::variant::object< Types... > const &_a, fcppt::variant::object< Types... > const &_b)
 Compares two variants for inequality.
 
template<typename... Elements>
std::string fcppt::variant::current_type_name (fcppt::variant::object< Elements... > const &_variant)
 Returns the type name of the current type.
 
template<fcppt::mpl::list::object_concept Types, fcppt::cast::dynamic_fun_concept Cast, typename Base >
fcppt::optional::object< fcppt::variant::from_list< fcppt::variant::dynamic_cast_types< Types > > > fcppt::variant::dynamic_cast_ (Base &_base)
 Tries several dynamic casts, returning a variant of their types.
 
template<typename Type , typename... Elements>
requires fcppt::variant::has_type_v<fcppt::variant::object<Elements...>,Type>
Type & fcppt::variant::get_unsafe (fcppt::variant::object< Elements... > &_object)
 Free get_unsafe function.
 
template<typename Type , typename... Elements>
requires fcppt::variant::has_type_v<fcppt::variant::object<Elements...>,Type>
Type const & fcppt::variant::get_unsafe (fcppt::variant::object< Elements... > const &_object)
 Free get_unsafe function.
 
template<typename Type , typename... Elements>
requires fcppt::variant::has_type_v<fcppt::variant::object<Elements...>, Type>
bool fcppt::variant::holds_type (fcppt::variant::object< Elements... > const &_variant)
 Checks if a type is held by a variant.
 
template<fcppt::variant::object_concept Variant, typename... Functions>
decltype(auto) fcppt::variant::match (Variant &&_variant, Functions const &..._functions)
 Matches a variant with a function for each element type.
 
template<typename... Types, typename Ch , typename Traits >
std::basic_ostream< Ch, Traits > & fcppt::variant::operator<< (std::basic_ostream< Ch, Traits > &_stream, fcppt::variant::object< Types... > const &_object)
 Outputs the value held by the variant to a basic_ostream.
 
template<typename Container >
fcppt::variant::partition_result< Container > fcppt::variant::partition (Container &&_container)
 Partitions a container of variants into multiple containers.
 
template<typename Type , fcppt::variant::object_concept Variant>
requires fcppt::variant::has_type_v<Variant,Type>
fcppt::optional::object< Type > fcppt::variant::to_optional (Variant &&_variant)
 Converts a variant and a type to an optional.
 
template<typename Type , fcppt::variant::object_concept Variant>
requires fcppt::variant::has_type_v<Variant,std::remove_const_t<Type>>
fcppt::optional::reference< Type > fcppt::variant::to_optional_ref (Variant &_variant)
 Converts a variant and a type to an optional reference.
 
template<typename... Types>
std::type_info const & fcppt::variant::type_info (fcppt::variant::object< Types... > const &_variant)
 Returns an std::type_info of the held type.
 

Variables

template<fcppt::variant::object_concept Variant, typename Element >
constexpr bool fcppt::variant::has_type_v = fcppt::variant::has_type<Variant,Element>::value
 Checks if a variant has a specific type.
 
template<typename T >
constexpr bool fcppt::variant::is_object_v = fcppt::variant::is_object<T>::value
 Checks if a given type is an fcppt::variant::object.
 

Typedef Documentation

◆ dynamic_cast_types

◆ from_list

◆ has_type

Checks if a variant has a specific type.

◆ partition_result

template<typename Container >
using fcppt::variant::partition_result
Initial value:

The result of fcppt::variant::partition.

Partitioning a Container<fcppt::variant::object<T_1,...,T_n>> yields fcppt::tuple::object<std::vector<T_1>,...,std::vector<T_n>>.

◆ size_type

using fcppt::variant::size_type = std::size_t

An integer type used to describe a type index.

See also
fcppt::variant::object::type_index

◆ types_of

template<fcppt::variant::object_concept Variant>
using fcppt::variant::types_of = typename fcppt::variant::detail::types_of<std::remove_cvref_t<Variant>>::type

The types of a variant.

Function Documentation

◆ apply()

template<typename Function , fcppt::variant::object_concept... Variants>
decltype(auto) fcppt::variant::apply ( Function const & _function,
Variants &&... _variants )
inlinenodiscard

Applies a function to the elements of several variants.

TODO(concepts)

◆ compare()

template<typename... Types, typename Compare >
bool fcppt::variant::compare ( fcppt::variant::object< Types... > const & _left,
fcppt::variant::object< Types... > const & _right,
Compare const & _compare )
inlinenodiscard

Compares two variants using a Compare function.

Compares _left and _right using _compare. The two variants are equal if they hold the same type T and _compare(_left.get<T>(), _right.get<T>()) holds.

Parameters
_leftThe first variant
_rightThe second variant
_compareThe function to use for comparison

◆ current_type_name()

template<typename... Elements>
std::string fcppt::variant::current_type_name ( fcppt::variant::object< Elements... > const & _variant)
nodiscard

Returns the type name of the current type.

◆ dynamic_cast_()

fcppt::optional::object< fcppt::variant::from_list< fcppt::variant::dynamic_cast_types< Types > > > fcppt::variant::dynamic_cast_ ( Base & _base)
nodiscard

Tries several dynamic casts, returning a variant of their types.

Let Types=(T_1,...,T_n). The function tries to cast _base to T_1 first. If this fails, it tries to cast _base to T_2, and so on. The result of the first cast that succeeds is returned.

Returns
An optional variant of types fcppt::reference<T_1>,...,fcppt::reference<T_n>.
Template Parameters
BaseThe base class type to cast from.

TODO(concepts)

◆ get_unsafe() [1/2]

template<typename Type , typename... Elements>
requires fcppt::variant::has_type_v<fcppt::variant::object<Elements...>,Type>
Type & fcppt::variant::get_unsafe ( fcppt::variant::object< Elements... > & _object)
inline

Free get_unsafe function.

Equal to _object.get<Type>().

See also
fcppt::variant::object::get_unsafe

◆ get_unsafe() [2/2]

template<typename Type , typename... Elements>
requires fcppt::variant::has_type_v<fcppt::variant::object<Elements...>,Type>
Type const & fcppt::variant::get_unsafe ( fcppt::variant::object< Elements... > const & _object)
inline

Free get_unsafe function.

Equal to _object.get<Type>().

See also
fcppt::variant::object::get_unsafe

◆ holds_type()

template<typename Type , typename... Elements>
requires fcppt::variant::has_type_v<fcppt::variant::object<Elements...>, Type>
bool fcppt::variant::holds_type ( fcppt::variant::object< Elements... > const & _variant)
inlinenodiscard

Checks if a type is held by a variant.

The currently held type of a variant is the type passed to its constructor or assignment operator. A type T can be held by a variant<Set> if T is a member of Set.

This function checks if Type is held by _variant.

Template Parameters
TypeThe type to check for which must be a possible type for the variant.

◆ match()

template<fcppt::variant::object_concept Variant, typename... Functions>
decltype(auto) fcppt::variant::match ( Variant && _variant,
Functions const &... _functions )
inline

Matches a variant with a function for each element type.

Matches _variant with _functions. The functions must be listed in the order the types appear in the variant.

TODO(concepts)

◆ operator!=()

template<typename... Types>
bool fcppt::variant::operator!= ( fcppt::variant::object< Types... > const & _a,
fcppt::variant::object< Types... > const & _b )
nodiscard

Compares two variants for inequality.

Compares _a and _b for inequality. Equal to !(_a == _b). This function requires all possible types of the variant to be equality comparable.

TODO(concepts)

◆ operator<<()

template<typename... Types, typename Ch , typename Traits >
std::basic_ostream< Ch, Traits > & fcppt::variant::operator<< ( std::basic_ostream< Ch, Traits > & _stream,
fcppt::variant::object< Types... > const & _object )
inline

Outputs the value held by the variant to a basic_ostream.

Outputs the value held by _object to _stream. This function requires all possibles types to be printable.

TODO(concepts)

◆ operator==()

template<typename... Types>
bool fcppt::variant::operator== ( fcppt::variant::object< Types... > const & _left,
fcppt::variant::object< Types... > const & _right )
nodiscard

Compares two variants for equality.

Compares _left and _right for equality. The two variants are equal if they hold the same type and the values compare equal. This function requires all possible types of the variant to be equality comparable.

TODO(concepts)

◆ partition()

template<typename Container >
fcppt::variant::partition_result< Container > fcppt::variant::partition ( Container && _container)
nodiscard

Partitions a container of variants into multiple containers.

Template Parameters
ContainerA container of fcppt::variant::object.

◆ to_optional()

template<typename Type , fcppt::variant::object_concept Variant>
requires fcppt::variant::has_type_v<Variant,Type>
fcppt::optional::object< Type > fcppt::variant::to_optional ( Variant && _variant)
nodiscard

Converts a variant and a type to an optional.

◆ to_optional_ref()

template<typename Type , fcppt::variant::object_concept Variant>
requires fcppt::variant::has_type_v<Variant,std::remove_const_t<Type>>
fcppt::optional::reference< Type > fcppt::variant::to_optional_ref ( Variant & _variant)
nodiscard

Converts a variant and a type to an optional reference.

◆ type_info()

template<typename... Types>
std::type_info const & fcppt::variant::type_info ( fcppt::variant::object< Types... > const & _variant)

Returns an std::type_info of the held type.

Variable Documentation

◆ has_type_v

template<fcppt::variant::object_concept Variant, typename Element >
bool fcppt::variant::has_type_v = fcppt::variant::has_type<Variant,Element>::value
inlineconstexpr

Checks if a variant has a specific type.

◆ is_object_v

template<typename T >
bool fcppt::variant::is_object_v = fcppt::variant::is_object<T>::value
inlineconstexpr

Checks if a given type is an fcppt::variant::object.