2.6.0
Freundlich's C++ toolkit
Classes | Functions
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, fcppt::cast::dynamic_exn
Casting between unrelated types fcppt::cast::dynamic_cross, fcppt::cast::dynamic_cross_exn
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
);
int const i(
int
>(
f
)
);
// prints 3
<< 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
T const _t
)
{
<<
_t
)
<< '\n';
}
void
g()
{
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:
// The constructor would normally be declared like this:
/*
explicit
my_class(
unsigned long
);
*/
// 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_(
unsigned long
>(
_other
)
)
{
}
private:
unsigned long 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(
10u
);
// 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(
10
);
*/
// Dito.
/*
my_class const test3(
-1
);
*/
// Conversions from floats don't work either.
/*
my_class const test4(
3.f
);
*/

fcppt::cast::safe is another cast that extends the set of types that fcppt::cast::safe_numeric can cast. If the types are both arithmetic types, then they will be converted using fcppt::cast::safe_numeric, otherwise they must be implicitly convertible. This is used for constructing strong typedefs, see strong typedefs.

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
{
// Try to cast the greatest unsigned long value into an unsigned int.
// This might fail or it might not fail depending on the
// implementation.
// fcppt::bad_truncation_check_cast will be thrown on failure.
unsigned const result(
unsigned
>(
std::numeric_limits<
unsigned long
>::max()
)
);
<< FCPPT_TEXT("The casted value is ")
<< result
<< FCPPT_TEXT('\n');
}
catch(
)
{
<< _error.string()
<< FCPPT_TEXT('\n');
}

Truncating conversions of negative values are also detected.

void
negative_conversion()
try
{
// -1 cannot be represented as an unsigned. This will throw an
// fcppt::bad_truncation_check_cast.
unsigned const result(
unsigned
>(
-1
)
);
<< FCPPT_TEXT("The casted value is ")
<< result
<< FCPPT_TEXT('\n');
}
catch(
)
{
<< _error.string()
<< FCPPT_TEXT('\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:

namespace
{
struct base
{
virtual ~base()
{}
};
struct derived1
:
base
{
};
struct derived2
:
base
{
};
void
f(
base &_base
)
{
derived2
> const to_d2{
derived2
>(
_base
)
};
derived1
> const to_d1{
derived1
>(
_base
)
};
<< to_d2.has_value()
<< ' '
<< to_d1.has_value()
<< '\n';
}
}

In case an exception is preferred, fcppt::cast::dynamic_exn can be used. The exception thrown includes std::type_index objects of the source and destination types.

#include <fcppt/text.hpp>
#include <fcppt/cast/bad_dynamic.hpp>
#include <fcppt/cast/dynamic_exn.hpp>
#include <fcppt/io/cout.hpp>
namespace
{
struct base
{
virtual
~base()
{}
};
struct derived1
:
base
{
};
struct derived2
:
base
{
};
void
f(
base &_base
)
{
try
{
// try to cast _base into a d2
derived2 &d2(
derived2 &
>(
_base
)
);
<< &d2
<< FCPPT_TEXT('\n');
}
catch(
)
{
// shows a nice message with the types in it
<< _error.string()
<< FCPPT_TEXT('\n');
}
}
}

To catch more mistakes, fcppt::cast::dynamic and fcppt::cast::dynamic_exn only work 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 and fcppt::cast::dynamic_cross_exn can be used:

namespace
{
struct base
{
virtual
~base()
{}
};
struct derived1
:
base
{
};
struct derived2
:
base
{
};
void
f(
derived1 &_d1
)
{
derived2
> const to_d2(
derived2
>(
_d1
)
);
<< 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.

typedef
float,
2
>
vec_2f;
typedef
int,
2
>
vec_2i;
auto const res(
vec_2i,
>(
vec_2f(
1.f,
2.f
)
)
);
<< res
<< '\n';

Classes

class  fcppt::cast::bad_dynamic
 May be thrown by fcppt::cast::dynamic if the cast fails. More...
 
class  fcppt::cast::bad_truncation_check
 May be thrown by fcppt::cast::truncation_check if the conversion truncates. More...
 
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...
 

Functions

template<typename Fun , typename Res , typename Src >
decltype(auto) constexpr fcppt::cast::apply (Src &&_src)
 Applies a cast to a source. More...
 
template<typename Derived , typename Base >
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. More...
 
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. More...
 
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. More...
 
template<typename Dest , typename Src >
std::enable_if< std::is_reference< Dest >::value, Dest >::type fcppt::cast::dynamic_cross_exn (Src &_src)
 Converts between references of unrelated types using dynamic_cast and provides additional error information. More...
 
template<typename Derived , typename Base >
std::enable_if< std::is_reference< Derived >::value, Derived >::type fcppt::cast::dynamic_exn (Base &_src)
 Converts between references of related types using dynamic_cast and provides additional error information. More...
 
template<typename Dest , typename Enum >
constexpr Dest fcppt::cast::enum_to_int (Enum const _enum) noexcept
 Converts an enum to an int. More...
 
template<typename Enum >
constexpr std::underlying_type< Enum >::type fcppt::cast::enum_to_underlying (Enum const _enum) noexcept
 Converts an enum to its underlying type. More...
 
template<typename Dest , typename Source >
Dest fcppt::cast::float_to_int (Source const _source) noexcept
 Converts a float to a signed int. More...
 
template<typename Dest , typename Source >
Dest fcppt::cast::from_void_ptr (Source *const _ptr) noexcept
 Converts a void pointer to a different pointer. More...
 
template<typename Enum , typename Source >
constexpr Enum fcppt::cast::int_to_enum (Source const _source) noexcept
 Converts an int to an enum. More...
 
template<typename Dest , typename Source >
Dest fcppt::cast::int_to_float (Source const _source) noexcept
 Converts an int to a float. More...
 
template<typename Type >
constexpr boost::promote< Type >::type fcppt::cast::promote (Type const _value) noexcept
 Casts a type to its promoted type. More...
 
template<typename Dest , typename Source >
constexpr Dest fcppt::cast::safe (Source const &_source)
 A cast that prohibits lossy conversions. More...
 
template<typename Dest , typename Source >
constexpr Dest fcppt::cast::safe_numeric (Source const &_source) noexcept
 Safe numeric cast is a safer static_cast that forbids lossy conversions. More...
 
template<typename Dest , typename Source >
constexpr Dest fcppt::cast::size (Source const _source) noexcept
 Converts a type to a similar type of different size. More...
 
template<typename Derived , typename Base >
Derived fcppt::cast::static_downcast (Base &_source) noexcept
 Statically converts a reference to a base class to a reference to a derived class. More...
 
template<typename Dest , typename Source >
Dest fcppt::cast::to_char_ptr (Source *const _source) noexcept
 Converts a pointer to a pointer to characters. More...
 
template<typename Type >
constexpr std::make_signed< Type >::type fcppt::cast::to_signed (Type const _value) noexcept
 Converts an unsigned int to its signed type. More...
 
template<typename Type >
constexpr std::make_unsigned< Type >::type fcppt::cast::to_unsigned (Type const _value) noexcept
 Converts a signed int to its unsigned type. More...
 
template<typename Type >
void fcppt::cast::to_void (Type const &_value) noexcept
 Casts an expression to void. More...
 
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. More...
 
template<typename Source >
void * fcppt::cast::to_void_ptr (Source *const _ptr) noexcept
 Converts a pointer to a pointer to void. More...
 
template<typename Dest , typename Source >
Dest fcppt::cast::truncation_check (Source const _source)
 Cast between integral types, checking for truncation. More...
 

Function Documentation

◆ apply()

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

Applies a cast to a source.

◆ dynamic()

template<typename Derived , typename Base >
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:

namespace
{
struct base
{
virtual ~base()
{}
};
struct derived1
:
base
{
};
struct derived2
:
base
{
};
void
f(
base &_base
)
{
derived2
> const to_d2{
derived2
>(
_base
)
};
derived1
> const to_d1{
derived1
>(
_base
)
};
<< 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:

namespace
{
struct base
{
virtual
~base()
{}
};
struct derived1
:
base
{
};
struct derived2
:
base
{
};
void
f(
derived1 &_d1
)
{
derived2
> const to_d2(
derived2
>(
_d1
)
);
<< 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

◆ dynamic_cross_exn()

template<typename Dest , typename Src >
std::enable_if< std::is_reference< Dest >::value, Dest>::type fcppt::cast::dynamic_cross_exn ( Src &  _src)
inline

Converts between references of unrelated types using dynamic_cast and provides additional error information.

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

Template Parameters
DestThe type to cast to. Must be a reference type. Must not inherit from Src.
SrcA cv-qualified non-reference type.
See also
fcppt::cast::dynamic_exn

◆ dynamic_exn()

template<typename Derived , typename Base >
std::enable_if< std::is_reference< Derived >::value, Derived>::type fcppt::cast::dynamic_exn ( Base &  _src)
inline

Converts between references of related types using dynamic_cast and provides additional error information.

Tries to cast _src to Derived using dynamic_cast. On failure, an fcppt::cast::bad_dynamic is thrown that includes additional information about the types involved. To catch more mistakes, Base must be a base class of Derived. In case you need a cross cast, use fcppt::cast::dynamic_cross_exn.

Here is an example:

#include <fcppt/text.hpp>
#include <fcppt/cast/bad_dynamic.hpp>
#include <fcppt/cast/dynamic_exn.hpp>
#include <fcppt/io/cout.hpp>
namespace
{
struct base
{
virtual
~base()
{}
};
struct derived1
:
base
{
};
struct derived2
:
base
{
};
void
f(
base &_base
)
{
try
{
// try to cast _base into a d2
derived2 &d2(
derived2 &
>(
_base
)
);
<< &d2
<< FCPPT_TEXT('\n');
}
catch(
)
{
// shows a nice message with the types in it
<< _error.string()
<< FCPPT_TEXT('\n');
}
}
}
Template Parameters
DerivedThe type to cast to. Must be a reference type. Must inherit from Base.
BaseA cv-qualified non-reference type.
Exceptions
fcppt::cast::bad_dynamicon failure

◆ enum_to_int()

template<typename Dest , typename Enum >
constexpr Dest fcppt::cast::enum_to_int ( Enum const  _enum)
inlinenoexcept

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 >
constexpr std::underlying_type< Enum>::type fcppt::cast::enum_to_underlying ( Enum const  _enum)
inlinenoexcept

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 >
Dest fcppt::cast::float_to_int ( Source const  _source)
inlinenoexcept

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 >
constexpr Enum fcppt::cast::int_to_enum ( Source const  _source)
inlinenoexcept

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 >
Dest fcppt::cast::int_to_float ( Source const  _source)
inlinenoexcept

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

template<typename Type >
constexpr boost::promote< Type>::type fcppt::cast::promote ( Type const  _value)
inlinenoexcept

Casts a type to its promoted type.

Converts _value to its promoted type. This can be used if explicit promotion is desired (e.g. when outputting to an ostream).

Template Parameters
TypeMust be a fundamental type

◆ safe()

template<typename Dest , typename Source >
constexpr Dest fcppt::cast::safe ( Source const &  _source)
inline

A cast that prohibits lossy conversions.

This cast converts arithmetic types like fcppt::cast::safe_numeric does. For every other type the conversion is done implicitly. More specifically, this means that for arithmetic types the restrictions of fcppt::cast::safe_numeric must hold, and for every other type Source must be implicitly convertible to Dest.

Template Parameters
DestCan be any type
SourceCan be any type

◆ safe_numeric()

template<typename Dest , typename Source >
constexpr Dest fcppt::cast::safe_numeric ( Source const &  _source)
noexcept

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 >
constexpr Dest fcppt::cast::size ( Source const  _source)
inlinenoexcept

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 >
Derived fcppt::cast::static_downcast ( Base &  _source)
noexcept

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 >
constexpr std::make_signed< Type>::type fcppt::cast::to_signed ( Type const  _value)
inlinenoexcept

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_unsigned()

template<typename Type >
constexpr std::make_unsigned< Type>::type fcppt::cast::to_unsigned ( Type const  _value)
inlinenoexcept

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 const* fcppt::cast::to_void_ptr ( Source const *const  _ptr)
inlinenoexcept

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

◆ to_void_ptr() [2/2]

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

Converts a pointer to a pointer to void.

◆ truncation_check()

template<typename Dest , typename Source >
Dest fcppt::cast::truncation_check ( Source const  _source)

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, otherwise fcppt::cast::bad_truncation_check is thrown.

Template Parameters
DestMust be an integral type
SourceMust be an integral type
Exceptions
fcppt::cast::bad_truncation_checkif truncation occurs