constexpr itoa

書きました。
constexpr なので、配列のポインタを渡して文字列を代入する事は出来ません。
処理した結果の文字列は固定長配列として返します。

[ソース]

#include <cstddef>
#include <limits>

namespace ce{

template<typename Char, std::size_t N>
struct c_string{
    Char elems[N ? N : 1];
    constexpr Char const* c_str() const{
        return &elems[0];
    }
};

template<std::size_t... Indices>
struct index_tuple{};

template<
    std::size_t Start,
    std::size_t Finish,
    std::size_t Step = 1,
    typename Acc = index_tuple<>,
    bool Break = (Start >= Finish)
>
struct index_range{
    typedef Acc type;
};

template<
    std::size_t Start, std::size_t Finish, std::size_t Step,
    std::size_t... Indices
>
struct index_range<Start, Finish, Step, index_tuple<Indices...>, false>
    : index_range<Start + Step, Finish, Step, index_tuple<Indices..., Start>>
{};

constexpr char
itoc(int n){
    return 0 <= n && n <= 9 ? '0' + n
        : '\0';
}

template<typename Char, std::size_t N, std::size_t ...Indices>
constexpr c_string<Char, N>
itoa_push_front_impl(Char const (&str)[N], index_tuple<Indices...>, Char c){
    return {{ c, str[Indices]..., '\0' }};
}

template<typename Char, std::size_t N>
constexpr c_string<Char, N>
itoa_push_front(Char const (&str)[N], Char c){
    return itoa_push_front_impl(str, typename index_range<0, N-2>::type(), c);
}

template<typename Char, std::size_t N>
constexpr c_string<Char, N>
itoa_push_front(c_string<Char, N> const& str, Char c){
    return itoa_push_front(str.elems, c);
}

template<typename T, typename String>
constexpr String
itoa_impl(T n, String const& str){
    return n == 0 ? str
        : itoa_impl(n/10, itoa_push_front(str, itoc(n%10)));
}

template<typename T, typename String>
constexpr auto
itoa(T n, String const& str)->decltype(itoa_impl(n, str)){
    return n < 0 ? itoa_push_front(itoa_impl(n*-1, str), '-')
         : itoa_impl(n, str);
}

template<typename T>
constexpr c_string<char, std::numeric_limits<T>::digits10+3>
itoa(T n){
    return itoa(n, c_string<char, std::numeric_limits<T>::digits10+3>{{}});
}


template<typename Char>
constexpr bool
equal(Char const* a, Char const* b){
    return a[0] == Char('\0') && b[0] == Char('\0') ? true
         : a[0] == b[0]                             ? equal(a+1, b+1)
         : false;
}

}  // namespace ce


#include <iostream>
#include <type_traits>

int
main(){
    static constexpr auto str = ce::itoa(94581048);
    static_assert(ce::equal(str.c_str(), "94581048"), "");

    static constexpr auto str2 = ce::itoa(-142);
    static_assert(ce::equal(str2.c_str(), "-142"), "");

    static constexpr auto str3 = ce::itoa(-142, ce::c_string<char, 10>{{}});
    static_assert(ce::equal(str3.c_str(), "-142"), "");

    static constexpr auto str4 = ce::itoa(-142, ce::c_string<char, 3>{{}});
    static_assert(ce::equal(str4.c_str(), "-1"), "");

    static constexpr auto str5 = ce::itoa(42, ce::c_string<char, 3>{{}});
    static_assert(ce::equal(str5.c_str(), "42"), "");

    static constexpr auto str6 = ce::itoa(2147483647);
    static_assert(ce::equal(str6.c_str(), "2147483647"), "");

    static constexpr auto str7 = ce::itoa(-2147483647);
    static_assert(ce::equal(str7.c_str(), "-2147483647"), "");

    static_assert(std::is_same<
        decltype(ce::itoa(10)),
        ce::c_string<char, 12>
    >::value, "");
    return 0;
}

んーこれで大丈夫かしら。
constexpr の文字列の扱いはまだまだですね…。

[コンパイラ]

  • g++ (GCC) 4.7.0 20110924 (experimental)