// pattern matching and type arithmetic in C++ // see https://en.wikipedia.org/wiki/Peano_axioms // see https://en.wikipedia.org/wiki/Successor_function // compile and test: "c++ peano.cpp -o peano && ./peano" // // zero is our first natural number // struct zero {}; // // all other natural numbers are either a successor of zero // or a successor of another successor // template // let's forget that type (see ::sum below) struct successor {}; // // sum = first + second // // non-empty declaration: this is the end of the recursion // (second is zero) template struct sum { using type = first; }; // recursive specialization // the pattern "successor" isn't matching zero // and is giving us the type of the predecessor we // forgot in the declaration of ::successor template struct sum> { // second is decremented by pattern matching using recursion = typename sum::type; // and the result is incremented using type = successor; }; // // product = multiplicand * multiplier // // non-empty declaration: this is the end of the recursion // (multiplier is zero) template struct product { using type = zero; }; // recursive specialization when multiplier isn't zero template struct product> { using recursion = typename product::type; using type = typename sum::type; }; // // difference = minuend - subtrahend // // empty declaration: compilation error if the result is negative template struct difference { }; // end of the recursion template struct difference { using type = minuend; }; // recursive specialization template struct difference, successor> { using recursion = difference; using type = typename recursion::type; }; // // quotient, remainder = dividend / divisor // namespace impl { // NOTE: for the division, we decrement divisor and // increment _remainder until divisor is zero, at // this point we increment the result, swap _remainder // with divisor to restore its value, until dividend is // zero and _remainder is the final remainder // empty declaration: compilation error when dividing by zero template struct quotient { }; // specialization when the dividend is zero, this is the end // of the recursion when the remainder isn't zero template struct quotient { using type = zero; using remainder = _remainder; }; // specialization when both dividend and divisor are zero, // the result is incremented and this is the end of the // recursion when the remainder is zero template struct quotient> { using type = successor; using remainder = zero; }; // recursive specialization when divisor is zero // the result is incremented and divisor is restored // from _remainder template struct quotient> { using recursion = quotient, zero>; using type = successor; using remainder = typename recursion::remainder; }; // recursive specialization template struct quotient, successor, _remainder> { using recursion = quotient>; using type = typename recursion::type; using remainder = typename recursion::remainder; }; } // namespace impl // let's hide the third parameter template using quotient = impl::quotient; // // natural_to_peano: convert from unsigned integer // template struct natural_to_peano { using recursion = typename natural_to_peano::type; using type = successor; }; template<> struct natural_to_peano<0u> { using type = zero; }; // // peano_to_natural: convert to unsigned integer // template struct peano_to_natural { enum : unsigned { value = 0u }; }; template struct peano_to_natural> { enum : unsigned { recursion = peano_to_natural::value, value = recursion + 1u }; }; // // now let's test! // #include int main () { using four = natural_to_peano<4u>::type; using six = natural_to_peano<6u>::type; using ten = sum::type; using fourty = product::type; using thirty_four = difference::type; // output: thirty_four = 34 printf("thirty_four = %u\n", peano_to_natural::value); // compilation error // using negative_difference = difference::type; using fourty_over_ten = quotient; using thirty_four_over_ten = quotient; // compilation errors: // using divide_by_zero = quotient; // printf("divide_by_zero = %u, %u\n", // peano_to_natural::value, // peano_to_natural::value); // output: fourty_over_ten = 4, 0 printf("fourty_over_ten = %u, %u\n", peano_to_natural::value, peano_to_natural::value); // output: thirty_four_over_ten = 3, 4 printf("thirty_four_over_ten = %u, %u\n", peano_to_natural::value, peano_to_natural::value); return 0; }