Convert char array to number C++17 have &lt;charconv&gt;. However this header does not work on MacOS - It compiles, but can not link. Same header is not present in MSVS. The header also missing from my Arm Linux, even my gcc compiler there supports C++17 as well.

Following is a take to convert non terminated char array (e.g. buffer, string_view etc) into signed or unsigned integer.

I probably will use the code in production, once I do some more tests.

#include &lt;limits&gt;
#include &lt;type_traits&gt;
#include &lt;string_view&gt;
#include &lt;utility&gt;

namespace impl{
    template&lt;typename T&gt;
    T x10(T a){
        return a * 10;
    }

    inline char digit(char c){
        return c - '0';
    }

    inline bool is_space(char c){
        return c == ' ' || c == '\t' || c == '\r' || c == '\n';
    }

    inline bool is_sign(char c){
        return c == '+' || c == '-';
    }

    inline bool is_digit(char c){
        return c &gt;= '0' &amp;&amp; c &lt;= '9';
    }

    template&lt;typename T&gt;
    std::pair&lt;bool,T&gt; convert_unsigned(const char *c, const char *e){
        T num = 0;

        while(c != e &amp;&amp; is_digit(*c)){
            T tmp = x10(num) + digit(*c);

            if (tmp &lt; num)
                return { false, num };

            num = tmp;

            ++c;
        }

        return { true, num };
    }

    template&lt;typename T&gt;
    std::pair&lt;bool,T&gt; convert(const char *c, const char *e, std::true_type /* unsigned */){
        if (c != e &amp;&amp; *c == '+')
            ++c;

        return convert_unsigned&lt;T&gt;(c, e);
    }

    template&lt;typename T&gt;
    std::pair&lt;bool,T&gt; convert(const char *c, const char *e, std::false_type /* unsigned */){
        using U = std::make_unsigned_t&lt;T&gt;;

        T sign = +1;
        U max  = std::numeric_limits&lt;T&gt;::max();

        if (c != e &amp;&amp; is_sign(*c)){
            if (*c == '-'){
                sign = -1;
                max  = - (U) std::numeric_limits&lt;T&gt;::min();
            }

            ++c;
        }

        // std::cout &lt;&lt; "&gt;&gt;&gt; " &lt;&lt; sign &lt;&lt; ' ' &lt;&lt; max &lt;&lt; ' ' &lt;&lt; '\n';

        auto [ ok, result ] = convert_unsigned&lt;U&gt;(c, e);

        if (result &gt; max)
            return { false, (T) result };

        if (result == max)
            return { true, (T) result };

        return { ok, sign * (T) result };
    }
}

template&lt;typename T&gt;
std::pair&lt;bool,T&gt; convert(std::string_view const s){
    static_assert(std::is_integral_v&lt;T&gt;);

    return impl::convert&lt;T&gt;(std::begin(s), std::end(s), std::is_unsigned&lt;T&gt;{});
}

#include &lt;cstdint&gt;
#include &lt;iostream&gt;

template&lt;typename T&gt;
void test(const char *s, T correct){
    auto [ok, i] = convert&lt;T&gt;(s);

    if (!ok)
        std::cout &lt;&lt; "Err" &lt;&lt; '\n';

    std::cout &lt;&lt; ( i == correct ? "OK" : "NO") &lt;&lt; ' ' &lt;&lt; i &lt;&lt; '\n';
}

int main(){
    test&lt;uint16_t&gt;  ("-0",              std::numeric_limits&lt;uint16_t&gt;::min()    );
    test&lt;uint16_t&gt;  ("65535",           std::numeric_limits&lt;uint16_t&gt;::max()    );
    test&lt;int16_t&gt;   ("+32767",          std::numeric_limits&lt;int16_t&gt;::max() );
    test&lt;int16_t&gt;   ("-32768",          std::numeric_limits&lt;int16_t&gt;::min() );
    test&lt;int16_t&gt;   ("+0",              0                   );
    test&lt;int16_t&gt;   ("-0",              0                   );
    test&lt;int16_t&gt;   ("+10",             +10                 );
    test&lt;int16_t&gt;   ("-10",             -10                 );

    test&lt;uint64_t&gt;  ("+0",                      std::numeric_limits&lt;uint64_t&gt;::min()    );
    test&lt;uint64_t&gt;  ("+18446744073709551615",   std::numeric_limits&lt;uint64_t&gt;::max()    );
    test&lt;int64_t&gt;   ("+9223372036854775807",    std::numeric_limits&lt;int64_t&gt;::max() );
    test&lt;int64_t&gt;   ("-9223372036854775808",    std::numeric_limits&lt;int64_t&gt;::min() );
}
We're missing any documentation or template constraints, but it appears that this code parses only decimal integers, and silently ignores anything after the first non-digit.  There are other departures from the interface of the functions provided in &lt;charconv&gt;:


a leading + is accepted and ignored
not all out-of-range values are detected.


Worse, there's no prevention of signed integer overflow, so there's undefined behaviour on certain inputs.
The avoidance of signed overflow is fragile and could be made clearer to the reader (with suitable static_assert() if requires isn't palatable, for instance).

I think that writing a function to multiply by 10 is taking functional decomposition a step too far.  I would say the same for subtracting '0', but that could be arguable if it were home for a comment explaining how C++ guarantees that the characters '0'..'9' are encoded as contiguous values.

There are no tests for any of the failure cases, and all the tests have to be checked externally.  It's better to make main() return an error status unless all the tests pass (and diagnostic output should go to std::clog or std::cerr as appropriate, rather than std::cout).