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