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