Last active
November 15, 2020 23:23
-
-
Save MaxBarraclough/3063379bc8562c16745eca070b230191 to your computer and use it in GitHub Desktop.
Demo of the type_safe C++ library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A small toy program to explore some of what we can do with the | |
// 'type_safe' library: https://github.com/foonathan/type_safe/ | |
// We will see that we can use it to create distinct new integer types, | |
// capable of ordinary arithmetic, and *without* implicit conversions. | |
// | |
// We will use this to implement Ada-style strong typing, protecting | |
// against confusing a NumApples_type value with a NumPennies_type value. | |
// | |
// See also the official examples: | |
// https://github.com/foonathan/type_safe/tree/master/example | |
#include <cstdint> // For fixed-width integer types | |
#include <cinttypes> // For printf specifiers | |
#include <cstdio> | |
#include <iostream> | |
#include <type_safe/strong_typedef.hpp> | |
namespace ts = type_safe; | |
struct Account { | |
struct NumApples_type | |
: ts::strong_typedef<NumApples_type, uint32_t>, | |
ts::strong_typedef_op::integer_arithmetic<NumApples_type>, | |
ts::strong_typedef_op::equality_comparison<NumApples_type>, | |
ts::strong_typedef_op::relational_comparison<NumApples_type> | |
{ | |
using strong_typedef::strong_typedef; | |
}; | |
struct NumPennies_type | |
: ts::strong_typedef<NumPennies_type, uint32_t>, | |
ts::strong_typedef_op::integer_arithmetic<NumPennies_type>, | |
ts::strong_typedef_op::equality_comparison<NumPennies_type>, | |
ts::strong_typedef_op::relational_comparison<NumPennies_type> | |
{ | |
using strong_typedef::strong_typedef; | |
}; | |
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_pennies | |
) | |
{ | |
if (order_quantity <= counterparty_ac.num_apples) | |
{ | |
if (order_payment_sum_pennies <= this->num_pennies) | |
{ | |
this->num_apples += order_quantity; // We don't bother to check for overflow. | |
counterparty_ac.num_apples -= order_quantity; // Cannot underflow as we checked <= | |
this->num_pennies -= order_payment_sum_pennies; // Cannot underflow as we checked <= | |
counterparty_ac.num_pennies += order_payment_sum_pennies; // 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."); | |
} | |
} | |
static inline void explore_the_types() | |
{ | |
// Let's look at what we can and can't do with these types | |
NumPennies_type test_pennies; | |
// test_pennies = 0; // Compile error. No implicit conversions, so this fails. | |
// test_pennies += 0; // Same again. | |
// NumPennies_type test_pennies2 = 0; // Compile error. | |
NumPennies_type test_pennies3(0); // Ok | |
NumApples_type test_apples(0); | |
// test_pennies3 += test_apples; // Compile error | |
// test_pennies3 = test_apples; // Compile error | |
} | |
}; | |
int main(int argc, char *argv[]) | |
{ | |
Account ac1(Account::NumApples_type(10), Account::NumPennies_type(10)); | |
Account ac2(Account::NumApples_type(100), Account::NumPennies_type(100)); | |
ac1.buy_apples(ac2, Account::NumApples_type(5), Account::NumPennies_type(7)); | |
// Account 1: Expect to see 15 apples and 3 pennies. | |
// Account 2: Expect to see 95 apples and 107 pennies. | |
// Whether we use the C way or the C++ way, we must explicitly cast. | |
// "%-10" to left align, padding to the right with spaces. UINT32_MAX is ten digits long. | |
printf("Account 1: Apples: %-10" PRIuLEAST32 " Pennies: %-10" PRIuLEAST32 "\n", (uint32_t)ac1.num_apples, (uint32_t)ac1.num_pennies); | |
printf("Account 2: Apples: %-10" PRIuLEAST32 " Pennies: %-10" PRIuLEAST32 "\n", (uint32_t)ac2.num_apples, (uint32_t)ac2.num_pennies); | |
// std::cout << "Account 1: Apples: " << (uint32_t)ac1.num_apples << " Pennies: " << (uint32_t)ac1.num_pennies << "\n"; | |
// std::cout << "Account 2: Apples: " << (uint32_t)ac2.num_apples << " Pennies: " << (uint32_t)ac2.num_pennies << "\n"; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment