Real-World Examples of Metaprogramming I
Learn about real-world examples of metaprogramming by implementing a generic safe cast function.
We'll cover the following
Advanced metaprogramming can appear very academic, so to demonstrate its usefulness, let’s look at some examples that demonstrate the syntax of metaprogramming and how it can be used in practice.
Example 1: creating a generic safe cast function
When casting between data types in C++, there is a multitude of different ways things can go wrong:
-
We might lose a value if casting to an integer type of a lower bit length.
-
We might lose a value if casting a negative value to an unsigned integer.
-
The correct address might become incorrect if casting from a pointer to any integer than
uintptr_t
. This is because C++ only guarantees thatuintptr_t
is the only integer type to withhold an address. -
If casting from
double
tofloat
, the result might beint
if thedouble
value is too large forfloat
to withhold. -
If casting between pointers with a
static_cast()
, we might get undefined behavior if the types aren’t sharing a common base class.
In order to make our code more robust, we can create a generic checked cast function that verifies our casts in debug mode and performs our casts as fast as possible if in release mode.
Depending on the types that are being cast, different checks are performed. If we try to cast between types that are not verified, it won’t compile.
These are the cases safe_cast()
is intended to handle:
-
Same type: If we’re casting the same type, we just return the input value.
-
Pointer to pointer: If casting between pointers,
safe_cast()
performs a dynamic cast in debug mode to verify it is castable. -
Double to floating point:
safe_cast()
accepts precision loss when casting fromdouble
tofloat
with one exception—if casting from adouble
to afloat
, there is a chance thedouble
is too large for thefloat
to handle the result. -
Arithmetic to arithmetic: If casting between arithmetic types, the value is cast back to its original type to verify no precision has been lost.
-
Pointer to non-pointer: If casting from a pointer to a non-pointer type,
safe_ cast()
verifies that the destination type is anuintptr_t
orintptr_t
, the only integer types that are guaranteed to hold an address.
In any other case, the safe_cast()
function fails to compile.
Implementation
Let’s see how we can implement this. We start by fetching information about our cast operation in constexpr
booleans. The reason they are constexpr
booleans and not const
booleans is that we will utilize them later in if constexpr
expressions, which require constexpr
conditions:
Get hands-on with 1200+ tech skills courses.