Skip to content

Instantly share code, notes, and snippets.

@MaxBarraclough
Last active November 15, 2020 19:59
Show Gist options
  • Save MaxBarraclough/088047135c1a1d7767f5ec82199c7815 to your computer and use it in GitHub Desktop.
Save MaxBarraclough/088047135c1a1d7767f5ec82199c7815 to your computer and use it in GitHub Desktop.
BOOST_STRONG_TYPEDEF Demo
// A small toy program (in fact it does nothing at all)
// to explore what we can do with BOOST_STRONG_TYPEDEF.
// We will see that it creates a distinct new type, with permissive
// implicit conversions regarding the original type.
//
// BOOST_STRONG_TYPEDEF has its uses, but we will see that we can't use
// BOOST_STRONG_TYPEDEF to implement Ada-style strong typing, such as to protect
// against confusing a NumApples_type value with a NumPennies_type value.
#include <cstdint>
#include <type_traits>
#include <array>
#include <vector>
#include <boost/serialization/strong_typedef.hpp>
struct Account {
BOOST_STRONG_TYPEDEF(uint32_t, NumApples_type)
BOOST_STRONG_TYPEDEF(uint32_t, NumPennies_type) // No need for floating-point
typedef uint32_t Typedef_uint32t; // Example ordinary typedef
// Let's confirm that ordinary typedefs work the way they always do,
// introducing an alias rather than a new type.
static_assert( std::is_same<Typedef_uint32t, uint32_t >::value );
// Let's confirm that BOOST_STRONG_TYPEDEF has given us new types,
// unlike an ordinary typedef.
static_assert( !std::is_same<NumApples_type, uint32_t >::value );
static_assert( !std::is_same<NumPennies_type, uint32_t >::value );
static_assert( !std::is_same<NumApples_type, NumPennies_type>::value );
NumApples_type num_apples;
NumPennies_type num_pennies;
inline Account(NumApples_type a, NumPennies_type p)
: num_apples(a), num_pennies(p)
{}
inline void buy_apples(
Account& counterparty_ac,
NumApples_type order_quantity,
NumPennies_type order_payment_sum
)
{
if (counterparty_ac.num_apples >= order_quantity)
{
if (this->num_pennies >= order_payment_sum)
{
this->num_apples += order_quantity; // We don't bother to check for overflow.
counterparty_ac.num_apples -= order_quantity; // Cannot underflow, as we checked for 0.
this->num_pennies -= order_payment_sum; // Cannot underflow as we checked for 0.
counterparty_ac.num_pennies += order_payment_sum; // We don't bother to check for overflow.
}
else
{
puts("Cannot transfer. Buyer lacks necessary funds.");
}
}
else
{
puts("Cannot transfer. Seller has too few apples.");
}
}
// Let's look at what we can and can't do with these types
static inline void explore_the_types()
{
NumPennies_type test_pennies;
NumApples_type test_apples(0);
// NumPennies_type test_pennies2 = 0; // Compile error.
NumPennies_type test_pennies2(0); // Ok
// These compile fine, as the type we get from BOOST_STRONG_TYPEDEF
// includes implicit conversion back to the 'original' type.
test_pennies = 0;
test_pennies += 42;
uint32_t test_pennies_uint32 = test_pennies;
// These two statements compile fine too.
// If we want to use type safety to prevent 'crossing the beams' in this way,
// BOOST_STRONG_TYPEDEF isn't the right tool.
// Instead we might consider the 'type_safe' library, see
// https://github.com/foonathan/type_safe/
// See also a whirlwind tour of it at
// https://gist.github.com/MaxBarraclough/3063379bc8562c16745eca070b230191
test_pennies = test_apples;
test_pennies += test_apples;
// Let's look at some collections from the C++ standard library
std::vector<NumPennies_type> pennies_vec;
std::vector<NumApples_type> apples_vec;
// pennies_vec = apples_vec;
// Compile error, due to invariance. See:
// * https://softwareengineering.stackexchange.com/a/399279/
// * https://cpptruths.blogspot.com/2015/11/covariance-and-contravariance-in-c.html
std::array<NumPennies_type,2> pennies_stdarr;
std::array<NumApples_type ,2> apples_stdarr;
// pennies_stdarr = apples_stdarr; // Compile error, same reason as above.
}
};
int main(int argc, char *argv[])
{
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment