Function to represent an integer in a base
n_to_digit doesn't really need to be a template, since its argument n can only ever be in the range 0 to 35. I'd just make it

char n_to_digit(int n) {
    static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
    return digits[n];
}


Notice also the replacement of *digits with digits[]; the optimizer will likely generate the same code either way, but without the optimizer's help, making digits the name of the array itself instead of the name of a pointer to the array will remove one level of pointer dereferencing.



YMMV, but I would find

std::array&lt;char, (sizeof(Integral) &lt;&lt; 3)&gt; str;


easier to read if it were just

char str[sizeof(Integral) * 8];


Of course then you'd have to use std::begin(str) instead of str.begin(). But you could make up for it by using it - str instead of std::distance(str.begin(), it).

Actually, hang on —

while (it != str.begin()) {
    *dst_it++ = *(--it);
}

return std::distance(str.begin(), it);


The loop never exits unless it == str.begin(), which means std::distance(str.begin(), it) == 0 by definition! This is certainly a bug.



Since you're trying to make this fully generic: note that *dst_it++ is going to be inefficient for a lot of iterator types. If you were writing this for a popular library, you'd write

*dst_it = '-';
++dst_it;


If you consistently avoid postfix operators, your users might even thank you, because your code will work even with their incompletely belled-and-whistled iterator types.



In the signed version, your use of std::abs(n) is a red flag. abs is never appropriate in generic code. For one thing, if Integral n is some clever fixed-point type, std::abs(n) won't compile; what you meant is more like

using std::abs;
... abs(n) ...


to pick up the correct abs through ADL. (But this opens the whole customization-point can of worms, which is still a mess even in C++17.)

No, the real reason abs is a red flag is because std::abs(-1 - 2147483647) invokes undefined behavior (source). You should never call abs on untrusted input.

The usual hack in this domain is to say

if (n &lt; 0) {
    *dst_it = '-'; ++dst_it;
} else {
    n = -n;
}


and then print the negative of n.



std::integral_constant&lt;bool, std::is_unsigned&lt;Integral&gt;::value&gt;()


could conceivably be written

typename std::is_unsigned&lt;Integral&gt;::type{}


but honestly, only the most evil and sadistic library implementation in the universe would make is_unsigned not derived from boolean_constant already. So you can just write

std::is_unsigned&lt;Integral&gt;{}


and be assured that your tag-dispatch code will work at least as well as your neighbor's. :)