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

Description

Cast helpers which provide more type information or do additional checks.

Motivation

C++ offers four different casts: static_cast, const_cast, reinterpret_cast and dynamic_cast which cover a wide area of explicit conversions. Some conversions can only be done by casts, e.g. dynamic_cast to cast in a polymorphic class hierarchy or reinterpret_cast to access the bytes of an object. static_cast can be used to reverse implicit conversions or make implicit conversions explicit. Therefore, static_cast does too many things at once, often hiding the intent of the programmer. Also, static_cast involves no checking which can be undesirable.

In order to fix these shortcomings, this module provides special casts, which highlight the intent of the programmer, and casts that check for truncation at compile time or at runtime.

Special Casts

Special casts are used to replace static_cast and reinterpret_cast where possible:

Casting between signed and unsigned integers fcppt::cast::to_signed, fcppt::cast::to_unsigned
Casting between types of the same signedness but different sizes fcppt::cast::size
Casting between floats and integers fcppt::cast::int_to_float, fcppt::cast::float_to_int
Casting between enums and integers fcppt::cast::int_to_enum, fcppt::cast::enum_to_int, fcppt::cast::enum_to_underlying
Casting between objects in a class hierarchy fcppt::cast::static_downcast, fcppt::cast::dynamic
Casting between unrelated types fcppt::cast::dynamic_cross
Casting from pointers to void fcppt::cast::from_void_ptr
Casting to a byte array fcppt::cast::to_char_ptr

Here is a small example:

float const f{3.5F};
// prints 3
std::cout << i << '\n';

An important thing to note is that these casts can't be used with the wrong types on accident:

template <typename T>
void test(T const _t)
{
std::cout << fcppt::cast::to_unsigned(_t) << '\n';
}
void g()
{
test(4);
// error:
// test(4u);
}

Safe conversions

fcppt::cast::safe_numeric is a cast that doesn't do any runtime checking (as opposed to fcppt::cast::truncation_check). Instead, it checks at compile time which conversions between arithmetic types are safe. See fcppt::cast::safe_numeric for a detailed description on which conditions must hold in order for the cast to compile.

The following example shows how a class's constructor can be strengthened by fcppt::cast::safe_numeric:

class my_class
{
public:
using int_type = unsigned long; // NOLINT(google-runtime-int)
// The constructor would normally be declared like this:
/*
explicit
my_class(int_type);
*/
// Use a templated constructor here so no implicit conversions take
// place when calling the constructor. The implicit conversions will be
// done by safe_numeric instead, and the unsafe ones will be
// forbidden.
template <typename Other>
explicit my_class(Other const &_other) : inner_(fcppt::cast::safe_numeric<int_type>(_other))
{
}
private:
int_type inner_;
};

Here are some examples of how the constructor can and can't be called:

// Ok, because an unsigned int can be converted to an unsigned long
my_class const test1(1U);
// Doesn't compile, because the signedness is different, although it
// would work at runtime. The value could as well be negative.
// my_class const test2(1);
// Dito.
// my_class const test3(-1);
// Conversions from floats don't work either.
// my_class const test4(3.f);

Checking truncation

fcppt::cast::truncation_check complements fcppt::cast::safe_numeric by checking at runtime if a conversion truncates.

In the following example, it is tested if the biggest unsigned long value fits into an unsigned int. This might be true, depending on the architecture.

void check_int_long()
{
// Try to cast the greatest unsigned long value into an unsigned int.
// This might fail or it might not fail depending on the
// implementation.
// An empty optional will be returned on failure.
std::numeric_limits<unsigned long // NOLINT(google-runtime-int)
>::max()));
std::cout << "The casted value is " << result << '\n';
}

Truncating conversions of negative values are also detected.

void negative_conversion()
{
// -1 cannot be represented as an unsigned. This will return nothing.
std::cout << "The casted value is " << result << '\n';
}

Dynamic casting

dynamic_cast can cast between pointers or references to objects in a class hierarchy. The cast can fail at runtime in which case the null pointer is returned for pointers and bad_cast is thrown for references. fcppt::cast::dynamic returns an empty optional on failure instead:

struct base
{
base() = default;
virtual ~base() = default;
};
struct derived1 : base
{
FCPPT_NONMOVABLE(derived1);
derived1() = default;
~derived1() override = default;
};
struct derived2 : base
{
FCPPT_NONMOVABLE(derived2);
derived2() = default;
~derived2() override = default;
};
void f(fcppt::reference<base> const _base)
{
std::cout << to_d2.has_value() << ' ' << to_d1.has_value() << '\n';
}

To catch more mistakes, fcppt::cast::dynamic only works on related types: The type to cast to must inherit from the source type. In case you need to cast between unrelated types, fcppt::cast::dynamic_cross can be used:

struct base
{
base() = default;
virtual ~base() = default;
};
struct derived1 : base
{
FCPPT_NONMOVABLE(derived1);
derived1() = default;
~derived1() override = default;
};
struct derived2 : base
{
FCPPT_NONMOVABLE(derived2);
derived2() = default;
~derived2() override = default;
};
void f(fcppt::reference<derived1> const _d1)
{
std::cout << to_d2.has_value() << '\n';
}

Casting user-defined types

For user-defined types static_cast and all of the casts from fcppt::cast can't be used directly. Instead, custom cast functions have to be defined. For example, fcppt.math defines functions called structure_cast to cast between vectors, dims and matrices. To incorporate cast functions from fcppt::cast, an additional template argument has to be added to the function's signature which then will be used to cast each element of the user-defined structure. For this purpose, this module defines several function objects suffixed with _fun, for example fcppt::cast::float_to_int_fun.

Classes

struct  fcppt::cast::dynamic_any_fun
 Function object that uses fcppt::cast::dynamic_any. More...
 
struct  fcppt::cast::dynamic_cross_fun
 Function object that uses fcppt::cast::dynamic_cross. More...
 
struct  fcppt::cast::dynamic_fun
 Function object that uses fcppt::cast::dynamic. More...
 
struct  fcppt::cast::float_to_int_fun
 Function object of fcppt::cast::float_to_int. More...
 
struct  fcppt::cast::int_to_enum_fun
 Function object of fcppt::cast::int_to_enum. More...
 
struct  fcppt::cast::int_to_float_fun
 Function object of fcppt::cast::int_to_float. More...
 
struct  fcppt::cast::size_fun
 Function object of fcppt::cast::size. More...
 
struct  fcppt::cast::static_cast_fun
 Function object that does a static_cast. More...
 
struct  fcppt::cast::to_signed_fun
 Function object of fcppt::cast::to_signed. More...
 
struct  fcppt::cast::to_unsigned_fun
 Function object of fcppt::cast::to_unsigned. More...
 

Typedefs

template<typename Type >
using fcppt::cast::promote_int_type = typename fcppt::cast::detail::promote_int_type<Type>::type
 The promoted type of an integral type.
 

Functions

template<typename Fun , typename Res , typename Src >
constexpr decltype(auto) fcppt::cast::apply (Src &&_src)
 Applies a cast to a source.
 
template<typename Derived , typename Base >
requires (fcppt::type_traits::is_base_of<std::remove_cv_t<Base>, std::remove_cv_t<Derived>>::value)
fcppt::optional::reference< Derived > fcppt::cast::dynamic (Base &_base) noexcept
 Converts between references of related types using dynamic_cast, returning an empty optional on failure.
 
template<typename Derived , typename Base >
fcppt::optional::reference< Derived > fcppt::cast::dynamic_any (Base &_base) noexcept
 Converts between references using dynamic_cast, returning an empty optional on failure.
 
template<typename Dest , typename Src >
fcppt::optional::reference< Dest > fcppt::cast::dynamic_cross (Src &_src) noexcept
 Tries a dynamic_cast on unrelated types, returning an empty optional on failure.
 
template<typename Dest , typename Enum >
requires (std::is_integral_v<Dest> && std::is_enum_v<Enum>)
constexpr Dest fcppt::cast::enum_to_int (Enum const _enum) noexcept
 Converts an enum to an int.
 
template<typename Enum >
requires std::is_enum_v<Enum>
constexpr std::underlying_type_t< Enum > fcppt::cast::enum_to_underlying (Enum const _enum) noexcept
 Converts an enum to its underlying type.
 
template<typename Dest , typename Source >
requires (std::is_floating_point_v<Source> && std::is_signed_v<Dest>)
constexpr Dest fcppt::cast::float_to_int (Source const _source) noexcept
 Converts a float to a signed int.
 
template<typename Dest , typename Source >
Dest fcppt::cast::from_void_ptr (Source *const _ptr) noexcept
 Converts a void pointer to a different pointer.
 
template<typename Enum , typename Source >
requires (std::is_enum_v<Enum> && std::is_integral_v<Source>)
constexpr Enum fcppt::cast::int_to_enum (Source const _source) noexcept
 Converts an int to an enum.
 
template<typename Dest , typename Source >
requires (std::is_integral_v<Source> && std::is_floating_point_v<Dest>)
constexpr Dest fcppt::cast::int_to_float (Source const _source) noexcept
 Converts an int to a float.
 
template<typename Type >
constexpr fcppt::cast::promote_int_type< Type > fcppt::cast::promote_int (Type const &_value)
 Promotes an integral type to int or unsigned int.
 
template<typename Dest , typename Source >
requires ( sizeof(Dest) >= sizeof(Source) && (std::is_same_v<Dest, Source> || (std::is_floating_point_v<Dest> && std::is_floating_point_v<Source>) || (std::is_integral_v<Dest> && std::is_integral_v<Source> && std::is_signed_v<Dest> == std::is_signed_v<Source>)))
constexpr Dest fcppt::cast::safe_numeric (Source const &_source) noexcept
 Safe numeric cast is a safer static_cast that forbids lossy conversions.
 
template<typename Dest , typename Source >
requires ( std::is_floating_point_v<Dest> == std::is_floating_point_v<Source> || std::is_signed_v<Dest> == std::is_signed_v<Source> || std::is_unsigned_v<Dest> == std::is_unsigned_v<Source>)
constexpr Dest fcppt::cast::size (Source const _source) noexcept
 Converts a type to a similar type of different size.
 
template<typename Derived , typename Base >
requires ( std::is_reference_v<Derived> && fcppt::type_traits::is_base_of<std::remove_cv_t<Base>, std::remove_cvref_t<Derived>>::value)
Derived fcppt::cast::static_downcast (Base &_source) noexcept
 Statically converts a reference to a base class to a reference to a derived class.
 
template<typename Dest , typename Source >
Dest fcppt::cast::to_char_ptr (Source *const _source) noexcept
 Converts a pointer to a pointer to characters.
 
template<typename Type >
requires std::is_unsigned_v<Type>
constexpr std::make_signed_t< Type > fcppt::cast::to_signed (Type const _value) noexcept
 Converts an unsigned int to its signed type.
 
template<typename Source >
std::uintptr_t fcppt::cast::to_uint_ptr (Source *const _ptr) noexcept
 Converts a pointer to a std::uintptr_t.
 
template<typename Type >
requires std::is_signed_v<Type>
constexpr std::make_unsigned_t< Type > fcppt::cast::to_unsigned (Type const _value) noexcept
 Converts a signed int to its unsigned type.
 
template<typename Type >
void fcppt::cast::to_void (Type const &_value) noexcept
 Casts an expression to void.
 
template<typename Source >
void const * fcppt::cast::to_void_ptr (Source const *const _ptr) noexcept
 Converts a pointer to const to a pointer to const void.
 
template<typename Source >
void * fcppt::cast::to_void_ptr (Source *const _ptr) noexcept
 Converts a pointer to a pointer to void.
 
template<typename Dest , typename Source >
requires (std::conjunction_v<std::is_integral<Source>, std::is_integral<Dest>>)
fcppt::optional::object< Dest > fcppt::cast::truncation_check (Source const _source)
 Cast between integral types, checking for truncation.
 

Typedef Documentation

◆ promote_int_type

template<typename Type >
using fcppt::cast::promote_int_type = typename fcppt::cast::detail::promote_int_type<Type>::type

The promoted type of an integral type.

Template Parameters
TypeMust be an integral type.

Function Documentation

◆ apply()

template<typename Fun , typename Res , typename Src >
decltype(auto) fcppt::cast::apply ( Src && _src)
constexpr

Applies a cast to a source.

◆ dynamic()

template<typename Derived , typename Base >
requires (fcppt::type_traits::is_base_of<std::remove_cv_t<Base>, std::remove_cv_t<Derived>>::value)
fcppt::optional::reference< Derived > fcppt::cast::dynamic ( Base & _base)
inlinenoexcept

Converts between references of related types using dynamic_cast, returning an empty optional on failure.

Tries to cast _src to Dest using dynamic_cast. On failure, an empty optional is returned. To catch more mistakes, Base must be a base class of Derived. In case you need a cross cast, use fcppt::cast::dynamic_cross.

Here is an example:

struct base
{
base() = default;
virtual ~base() = default;
};
struct derived1 : base
{
FCPPT_NONMOVABLE(derived1);
derived1() = default;
~derived1() override = default;
};
struct derived2 : base
{
FCPPT_NONMOVABLE(derived2);
derived2() = default;
~derived2() override = default;
};
void f(fcppt::reference<base> const _base)
{
std::cout << to_d2.has_value() << ' ' << to_d1.has_value() << '\n';
}
Template Parameters
DerivedThe type to cast to. Can be cv-qualified. Must inherit from Base.
BaseA cv-qualified non-reference type.
See also
fcppt::cast::dynamic_cross

◆ dynamic_any()

template<typename Derived , typename Base >
fcppt::optional::reference< Derived > fcppt::cast::dynamic_any ( Base & _base)
inlinenoexcept

Converts between references using dynamic_cast, returning an empty optional on failure.

Tries to cast _src to Dest using dynamic_cast. On failure, an empty optional is returned.

Template Parameters
DerivedThe type to cast to. Can be cv-qualified.
BaseA cv-qualified non-reference type.

◆ dynamic_cross()

template<typename Dest , typename Src >
fcppt::optional::reference< Dest > fcppt::cast::dynamic_cross ( Src & _src)
inlinenoexcept

Tries a dynamic_cast on unrelated types, returning an empty optional on failure.

This cast is the same as fcppt::cast::dynamic but only works on unrelated types.

Here is an example:

struct base
{
base() = default;
virtual ~base() = default;
};
struct derived1 : base
{
FCPPT_NONMOVABLE(derived1);
derived1() = default;
~derived1() override = default;
};
struct derived2 : base
{
FCPPT_NONMOVABLE(derived2);
derived2() = default;
~derived2() override = default;
};
void f(fcppt::reference<derived1> const _d1)
{
std::cout << to_d2.has_value() << '\n';
}
Template Parameters
DestThe type to cast to. Can be cv-qualified. Must not inherit from Base.
SrcA cv-qualified non-reference type.
See also
fcppt::cast::dynamic

◆ enum_to_int()

template<typename Dest , typename Enum >
requires (std::is_integral_v<Dest> && std::is_enum_v<Enum>)
Dest fcppt::cast::enum_to_int ( Enum const _enum)
constexprnoexcept

Converts an enum to an int.

Converts _enum to the integer type specified by Dest. This cast is unsafe and should only be used if the enum value can be converted to the destination type. Consider fcppt::cast::enum_to_underlying instead.

Template Parameters
DestMust be an integral type
EnumMust be an enumeration type

◆ enum_to_underlying()

template<typename Enum >
requires std::is_enum_v<Enum>
std::underlying_type_t< Enum > fcppt::cast::enum_to_underlying ( Enum const _enum)
constexprnoexcept

Converts an enum to its underlying type.

Converts _enum to its underlying integer type. This cast is safe.

Template Parameters
EnumMust be an enumeration type

◆ float_to_int()

template<typename Dest , typename Source >
requires (std::is_floating_point_v<Source> && std::is_signed_v<Dest>)
Dest fcppt::cast::float_to_int ( Source const _source)
constexprnoexcept

Converts a float to a signed int.

Converts _source to an integer. The function ensures that only signed integers can be used as destination types. If you need to cast to unsigned integers, use fcppt::cast::to_unsigned in addition. This cast is unsafe and should be used with care.

Template Parameters
SourceMust be a floating point type
DestMust be a signed integer type

◆ from_void_ptr()

template<typename Dest , typename Source >
Dest fcppt::cast::from_void_ptr ( Source *const _ptr)
inlinenoexcept

Converts a void pointer to a different pointer.

Converts the void pointer _ptr to the pointer type specified by Dest. This cast is unsafe.

Template Parameters
SourceMust be a pointer type to (cv) void
DestMust be a pointer type

◆ int_to_enum()

template<typename Enum , typename Source >
requires (std::is_enum_v<Enum> && std::is_integral_v<Source>)
Enum fcppt::cast::int_to_enum ( Source const _source)
constexprnoexcept

Converts an int to an enum.

Converts the integer _source to the enum type specified by Enum. This cast is unsafe and should only be used if the enum can actually hold the integer value. Consider using fcppt::cast_to_enum instead.

Template Parameters
SourceMust be an integral type
EnumMust be an enumeration type

◆ int_to_float()

template<typename Dest , typename Source >
requires (std::is_integral_v<Source> && std::is_floating_point_v<Dest>)
Dest fcppt::cast::int_to_float ( Source const _source)
constexprnoexcept

Converts an int to a float.

Converts the integer _source to the float type specified by Dest by truncating like static_cast. This cast is unsafe and should be used with care.

Template Parameters
SourceMust be an integral type
DestMust be a floating point type

◆ promote_int()

template<typename Type >
fcppt::cast::promote_int_type< Type > fcppt::cast::promote_int ( Type const & _value)
constexpr

Promotes an integral type to int or unsigned int.

Template Parameters
TypeMust be an integral type.

◆ safe_numeric()

template<typename Dest , typename Source >
requires ( sizeof(Dest) >= sizeof(Source) && (std::is_same_v<Dest, Source> || (std::is_floating_point_v<Dest> && std::is_floating_point_v<Source>) || (std::is_integral_v<Dest> && std::is_integral_v<Source> && std::is_signed_v<Dest> == std::is_signed_v<Source>)))
Dest fcppt::cast::safe_numeric ( Source const & _source)
constexprnoexcept

Safe numeric cast is a safer static_cast that forbids lossy conversions.

This cast converts one arithmetic type to another, where the size of the destination type must be at least the size of the source type.

Furthermore, the conversion is only allowed if and only if one of the following cases hold true:

  • Both types are the same type

  • Both types are integer types and both have the same signedness

  • Both types are floating point types

Template Parameters
DestThe destination type of the conversion
SourceThe source type of the conversion

◆ size()

template<typename Dest , typename Source >
requires ( std::is_floating_point_v<Dest> == std::is_floating_point_v<Source> || std::is_signed_v<Dest> == std::is_signed_v<Source> || std::is_unsigned_v<Dest> == std::is_unsigned_v<Source>)
Dest fcppt::cast::size ( Source const _source)
constexprnoexcept

Converts a type to a similar type of different size.

Converts _source to the type specified by Dest. Exactly one of the following cases must hold:

  • Both types are signed integer types.

  • Both types are unsigned integer types.

  • Both types are floating point types.

◆ static_downcast()

template<typename Derived , typename Base >
requires ( std::is_reference_v<Derived> && fcppt::type_traits::is_base_of<std::remove_cv_t<Base>, std::remove_cvref_t<Derived>>::value)
Derived fcppt::cast::static_downcast ( Base & _source)
inlinenoexcept

Statically converts a reference to a base class to a reference to a derived class.

Converts _source to the reference type specified by Derived. This cast is unsafe and should only be used if the _source has a dynamic type which is a subtype of Derived. Consider using fcppt::cast::dynamic instead.

Derived must be a reference to a class type derived from Base.

Template Parameters
DerivedThe type to cast to. Must be a reference type. Must inherit from Base.
BaseA cv-qualified non-reference type.

◆ to_char_ptr()

template<typename Dest , typename Source >
Dest fcppt::cast::to_char_ptr ( Source *const _source)
inlinenoexcept

Converts a pointer to a pointer to characters.

Converts _source to the pointer to character type specified by Dest. This cast can be used to access the byte representation of an object, e.g. for serialization, and largely replaces reinterpret_cast.

Template Parameters
DestMust be a pointer to (cv) unsigned char

◆ to_signed()

template<typename Type >
requires std::is_unsigned_v<Type>
std::make_signed_t< Type > fcppt::cast::to_signed ( Type const _value)
constexprnoexcept

Converts an unsigned int to its signed type.

Converts _value to its signed type. This cast is unsafe and should only be used if _value fits into the result.

Template Parameters
TypeMust be an unsigned type

◆ to_uint_ptr()

template<typename Source >
std::uintptr_t fcppt::cast::to_uint_ptr ( Source *const _ptr)
inlinenoexcept

Converts a pointer to a std::uintptr_t.

◆ to_unsigned()

template<typename Type >
requires std::is_signed_v<Type>
std::make_unsigned_t< Type > fcppt::cast::to_unsigned ( Type const _value)
constexprnoexcept

Converts a signed int to its unsigned type.

Converts _value to its unsigned type. This cast is unsafe and should only be used if _value is positive.

Template Parameters
TypeMust be a signed type

◆ to_void()

template<typename Type >
void fcppt::cast::to_void ( Type const & _value)
inlinenoexcept

Casts an expression to void.

Casts _value to void, ignoring the expression. This is useful if you want to avoid using an expression, for example if an expression is used to do static type checking (e.g. for completeness).

Template Parameters
TypeCan be any object type
Parameters
_valueThe value to cast to void

◆ to_void_ptr() [1/2]

template<typename Source >
void * fcppt::cast::to_void_ptr ( Source *const _ptr)
inlinenoexcept

Converts a pointer to a pointer to void.

◆ to_void_ptr() [2/2]

template<typename Source >
void const * fcppt::cast::to_void_ptr ( Source const *const _ptr)
inlinenoexcept

Converts a pointer to const to a pointer to const void.

◆ truncation_check()

template<typename Dest , typename Source >
requires (std::conjunction_v<std::is_integral<Source>, std::is_integral<Dest>>)
fcppt::optional::object< Dest > fcppt::cast::truncation_check ( Source const _source)
inline

Cast between integral types, checking for truncation.

Casts _source of type Source to the type Dest. It returns the converted value iff the conversion results in no truncation.

Template Parameters
DestMust be an integral type
SourceMust be an integral type