constexpr atoi で最後に処理した文字列の位置を返す

atoi 関数には元々そんな機能はありませんが、ちょっと実験的に試してみました。
具体的にいうと strtol 関数の第二引数に当たる処理ですね。

[ソース]

#include <cstdlib>
#include <iostream>

namespace ce{

template<typename Char>
constexpr int
ctoi(Char c){
    return Char('0') <= c && c <= Char('9')
        ? c - Char('0')
        : -1;
}

template<typename Char>
struct atoi_result{
    constexpr atoi_result(int value, Char const* str)
        : value(value), str(str){}
    constexpr operator int () const{
        return value;
    }
    constexpr Char const* c_str() const{
        return str;
    }
private:
    int value;
    Char const* str;
};

template<typename Char>
constexpr atoi_result<Char>
minus(atoi_result<Char> const& value){
    return atoi_result<Char>(value * -1, value.c_str());
}

template<typename Char>
constexpr atoi_result<Char>
atoi_impl(Char const* s, int sum){
	return ctoi(s[0]) == -1 ? atoi_result<Char>(sum, s)
		 : atoi_impl(s + 1, sum * 10 + ctoi(s[0]));
}

template<typename Char>
constexpr atoi_result<Char>
atoi(Char const* s){
    return s[0] == Char('-')
        ? minus(atoi_impl(s + 1, 0))
        : atoi_impl(s, 0);
}

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

int
main(){
    static constexpr char str[] = "42faa";
    static constexpr auto result = ce::atoi(str);
    static_assert(ce::atoi("42") == 42, "");
    static_assert(ce::equal(result.c_str(), "faa"), "");

    // 一時変数を渡すと…
    static constexpr auto result2 = ce::atoi("-45qor");
    // OK
    static_assert(result2 == -45, "");
    // これも OK???
    static_assert(ce::equal(result2.c_str(), "qor"), "");
    // 実行時にポインタの指している先はすでに無いので NG
    // std::cout << result2.c_str() << std::endl;

    return 0;
}

constexpr では、関数の引数に結果を代入することが出来ないので、数値と文字列の位置をクラスオブジェクトとして返しています。
一時変数の場合はポインタがぶっ飛んでしまうのが、ぐぬぬ…。
文字列をコピーして保持するような処理にするべきなんだろうけども、さて。

[コンパイラ]

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