C++でC風ライブラリを作る(文字列→整数変換編2)
高木です。こんばんは。
前回予告したように、今回は文字列から符合無し整数への変換を完成させることにします。
前回使ったtolower
関数もそうなのですが、今回も以前、文字種別編で作った関数を有効活用していきます。
ただし、完成とはいっても、ボリュームの関係でエラー処理は次回まわしにしたいと思います。
それでは早速実装に入っていきます。
まずは、先行する空白類文字を読み飛ばし、符合を解釈するためのヘルパー関数space_sign
から作っていきましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | namespace cloverfield { namespace detail { template <typename Iterator> bool space_sign(Iterator& next, Iterator last) { using char_type = typename std::iterator_traits<Iterator>::value_type; bool sign = false; for (; next != last; ++next) { switch (auto c = *next) { case char_type('-'): sign = true; case char_type('+'): ++next; return sign; default: if (!isspace(c)) return false; break; } } return false; } } } |
次に、Radix
に0を指定した場合は接頭辞を解析して基数を設定する必要がありますので、これもヘルパー関数を用意しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | namespace cloverfield { namespce detail { template <typename Iterator> int radix_prefix(Iterator& next, Iterator last) { using char_type = typename std::iterator_traits<Iterator>::value_type; if (next != last) { if (*next == char_type('0')) { if (++next != last) { switch (*next) { case char_type('b'): ++next; return 2; case char_type('x'): ++next; return 16; default: break; } } return 8; } } return 10; } } } |
そして、これらを使ってstrto
関数テンプレートを実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | namespace cloverfield { template <typename Type, int Radix, typename Iterator> Type strto(Iterator first, Iterator last, Iterator* endit) { bool sign = detail::space_sign(first, last); Type u; if (Radix == 0) { switch (detail::radix_prefix(first, last)) { case 2: u = detail::strto_helper<Type, 2>(first, last, endit); break; case 8: u = detail::strto_helper<Type, 8>(first, last, endit); break; case 16: u = detail::strto_helper<Type, 16>(first, last, endit); break; default: u = detail::strto_helper<Type, 10>(first, last, endit); break; } } else { u = detail::strto_helper<Type, Radix>(first, last, endit); } return sign? -u : u; } } |
前回、strto_helper
関数テンプレート内で、
static_assert
を用いて基数を2~36に制限しましたが、これをやるとstrto
関数テンプレートにRadix
を0にして呼び出す際にエラーになってしまいますので、いったん除去することにします。
必要なら、0も許可する形にしないといけませんね。
今回で完成まで持っていこうと思ったのですが、ちょっと長くなりすぎました。
次回もう1回だけ時間を取って、最後まで完成させたいと思います。
残作業としては、利便性を向上させるためにいくつかのバリエーションを多重定義することと、エラー処理です。
オーバーフローが発生した場合の処理をもう少し頑張りたいと思います。