constexpr atof
書きました。
一応、文字列の最後の位置も返すようにしたのですが、strtod と比べて挙動が違ってしまっているので、ぐぬぬ…。
ここら辺は一度、設計を見直す必要がありますねぇ(´・ω・`)
文字列の位置を保持するのは難しい…。
[ソース]
#include <cstdlib> #include <iostream> namespace ce{ template<typename Char> constexpr int ctoi(Char c){ return Char('0') <= c && c <= Char('9') ? c - Char('0') : Char(-1); } template<typename T, typename Char> struct with_c_str{ constexpr with_c_str(T value, Char const* str) : value(value), str(str){} constexpr operator T() const{ return value; } constexpr T get() const{ return value; } constexpr Char const* c_str() const{ return str; } private: T value; Char const* str; }; template<typename T, typename Char> constexpr with_c_str<T, Char> minus(with_c_str<T, Char> const& value){ return with_c_str<T, Char>(value * -1, value.c_str()); } template<typename T, typename Char> constexpr with_c_str<T, Char> operator *(T t, with_c_str<T, Char> const& value){ return with_c_str<T, Char>(t * value.get(), value.c_str()); } template<typename T, typename Char> constexpr with_c_str<T, Char> operator /(T t, with_c_str<T, Char> const& value){ return with_c_str<T, Char>(t / value.get(), value.c_str()); } template<typename Char> constexpr Char const* remove_space(Char const* s){ return s[0] != Char(' ') ? s : remove_space(s+1); } template<typename Char> constexpr bool isdigit(Char c){ return Char('0') <= c && c <= Char('9'); } template<typename Char, typename Result = with_c_str<int, Char>> constexpr Result atoi_impl(Char const* s, int tmp){ return ctoi(s[0]) == -1 ? Result(tmp, s) : atoi_impl(s + 1, tmp * 10 + ctoi(s[0])); } template<typename Char, typename Result = with_c_str<int, Char>> constexpr Result atoi_sign(Char const* s){ return s[0] != Char('-') ? atoi_impl(s, 0) : isdigit(s[1]) ? minus(atoi_impl(s + 1, 0)) : Result(0, s); } template<typename Char> constexpr auto atoi(Char const* s)->decltype(atoi_sign(remove_space(s))){ return atoi_sign(remove_space(s)); } 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; } constexpr double pow(double x, unsigned int y){ return y <= 1 ? x : x * pow(x, y-1); } constexpr int keta(int n, int sum = 0){ return n <= 0 ? sum : keta(n/10, sum+1); } template<typename T, typename Char, typename Result = with_c_str<double, Char>> constexpr Result atof_power_impl(with_c_str<T, Char> const& n){ return n == 0 ? Result(1, n.c_str()) : n == 0 ? Result(1, n.c_str()) : n > 0 ? Result(pow(10.0, n), n.c_str()) : Result(1 / pow(10.0, n*-1), n.c_str()); } template<typename Char> constexpr bool isdigit_plus_minus(Char c){ return (Char('0') <= c && c <= Char('9')) || c == Char('-') || c == Char('+'); } template<typename Char, typename Result = with_c_str<double, Char>> constexpr Result atof_power(Char const* s){ return (s[0] == Char('e') || s[0] == Char('E')) && atoi(s+1).c_str() != (s+1) ? atof_power_impl(atoi(s+1)) : Result(1, s); } template<typename T, typename Char, typename Result = with_c_str<double, Char>> constexpr Result atof_impl(with_c_str<T, Char> const& n, double sum){ return (n / pow(10.0, keta(n)) + sum) * atof_power(n.c_str()); } template<typename Char, typename Result = with_c_str<double, Char>> constexpr Result atof_dot(Char const* s, int sum){ return s[0] == Char('.') ? atof_impl(atoi(s+1), sum) : Result(sum, s); } template<typename T, typename Char, typename Result = with_c_str<double, Char>> constexpr Result atof(with_c_str<T, Char> const& atoi){ return atoi < 0 ? minus(atof_dot(atoi.c_str(), -atoi)) : atof_dot(atoi.c_str(), atoi); } template<typename Char> constexpr auto atof(Char const* s)->decltype(atof(atoi(s))){ return atof(atoi(s)); } } // namespace ce #include <cstdlib> int main(){ static_assert(ce::atof("53.132") == 53.132, ""); static_assert(ce::atof("42") == 42, ""); static_assert(ce::atof("0.14035") == 0.14035, ""); static_assert(ce::atof("") == 0, ""); static_assert(ce::atof(".") == 0, ""); static_assert(ce::atof("3...14") == 3, ""); static_assert(ce::atof(" -3.14") == -3.14, ""); static_assert(ce::atof("0.25e2") == 25, ""); static_assert(ce::atof("24.25E4") == 242500, ""); static_assert(ce::atof("0.25e2") == 25, ""); static_assert(ce::atof("0.4e-2") == 0.004, ""); static constexpr auto result = ce::atof("24.25EE4"); static_assert(result == 24.25, ""); static_assert(ce::equal(result.c_str(), "EE4"), ""); static constexpr auto result2 = ce::atof("0.25e-"); static_assert(result2 == 0.25, ""); static_assert(ce::equal(result2.c_str(), "e-"), ""); static constexpr auto result3 = ce::atof("0.25e -"); static_assert(result3 == 0.25, ""); // strtod の仕様だと OK // static_assert(ce::equal(result4.c_str(), "e -"), ""); return 0; }
他人(=明日の自分)が読める気がしない…!