Extended Euclidean Algorithm in modern and readable C++ In Python the Extended Euclidean Algorithm (egcd) could be written as follows:

def egcd(a, b):
  if b == 0:
    return (a, 1, 0)
  else:
    (d, tmp, s) = egcd(b, a%b)
    return (d, s, tmp - (a//b) * s)


I want to write a native and modern C++ version of the egcd. This is what I have so far:

template&lt;typename A, typename B, typename T = std::common_type_t&lt;A, B&gt;&gt;
constexpr std::tuple&lt;T, T, T&gt; egcd(A a, B b) {
  static_assert(std::is_integral&lt;A&gt;::value, "arguments to egcd are integers");
  static_assert(std::is_integral&lt;B&gt;::value, "arguments to egcd are integers");

  if (b == 0) {
    return std::make_tuple(a, 1, 0);
  } else {
    auto triple = egcd(b, a%b);
    return std::make_tuple(std::get&lt;0&gt;(triple), std::get&lt;2&gt;(triple), std::get&lt;1&gt;(triple) - (a/b) * std::get&lt;2&gt;(triple))
  }
}


As you can see using &lt;tuple&gt; makes the code very long and hard (compare with the Python version..) to read.

Any suggestions to make this code more readable?
The code is rather tiny so there isn't much to say, but I still have a couple of remarks:


Since you're using C++17, you can take advantage of variable templates to simplify your static assertions a bit:

static_assert(std::is_integral_v&lt;A&gt;, "arguments to egcd are integers");
static_assert(std::is_integral_v&lt;B&gt;, "arguments to egcd are integers");

The LWG issues 2733 and 2759 highlight the fact that any possibly cv-qualified bool satisfies the std::is_integral trait, but the GCD and LCM operations don't make much sense for boolean types. Consequently, the extended operations don't make much sense for boolean types eithers. You could add the following static assertions to make it clear:

static_assert(not std::is_same_v&lt;std::decay_t&lt;A&gt;, bool&gt;, "arguments to egcd are not booleans");
static_assert(not std::is_same_v&lt;std::decay_t&lt;B&gt;, bool&gt;, "arguments to egcd are not booleans");

Since you're always computing both a / b and a % b, you can compute std::div instead which computes both at once and returns a structure with quot and rem members. Actually, the algorithm used to compute the remainder of a and b also computes the quotient of a and b, so functions like std::div exist in several programming languages so that users can take advantage of it instead of discarding a computed value and computing it again.
They're not widely available at the moment, but if you intend to keep returning an std::tuple, a C++17 decomposition declaration would probably make your code more readable by providing explicit names instead of the opaque std::get&lt;position&gt;:

if (b == 0) {
    return std::make_tuple(a, 1, 0);
} else {
    auto divmod = std::div(a, b);
    auto [gcd, bezout_x, bezout_y] = egcd(b, divmod.rem);
    return std::make_tuple(gcd, bezout_y, bezout_x - divmod.quot * bezout_y)
}