C++でC風ライブラリを作る(文字列比較編2)
高木です。おはようございます。
前回に引き続き、文字列比較編です。
今回は実際のコードを紹介していくことにします。
そういえば前回、strcoll
関数相当のものは面倒なので割愛すると書きました。
実際にはstd::collate
を使えば簡単に実装することはできます。
ただ、そもそも使用頻度が低いということもありますし、現在作っているライブラリはロケールの切り替えを想定していないということもあります。
また、仮にロケールを切り替えるにしても、私が普段よく使う処理系のひとつであるMinGW-w64はstd::localeで設定できるのはCロケールしかないという問題もあります。
そういうこともあって、やはりstrcoll
関数相当のものは割愛ということにしたいと思います。
それでは順に実装していくことにします。
まずは基本からということで、ナル終端文字列どうしの単純比較からです。
まあ、素直な作りですね。
なお、char
型とwchar_t
型の文字列については多重定義することにします。
とくにchar
型の文字列を扱うstd::strcmp
関数はビルトイン関数のこともあるので標準ライブラリを使う方が性能がよいことも多いと思います。
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 | namespace cloverfield { template <typename charT> inline int strcmp(charT const* s1, charT const* s2) { auto ss1 = s1; auto ss2 = s2; while (*ss1 && *ss1 == *ss2) { ++ss1; ++ss2; } return *ss1 - *ss2; } inline int strcmp(char const* s1, char const* s2) { return std::strcmp(s1, s2); } inline int strcmp(wchar_t const* s1, wchar_t const* s2) { return std::wcscmp(s1, s2); } } |
続いて、一方または両方がstd::basic_string
クラステンプレートの場合について多重定義することにしましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | namespace cloverfield { template <typename charT, typename traits, typename Allocator1, typename Allocator2> inline int strcmp(std::basic_string<charT, traits, Allocator1> const& s1, std::basic_string<charT, traits, Allocator2> const& s2) { return strcmp(s1.c_str(), s2.c_str()); } template <typename charT, typename traits, typename Allocator> inline int strcmp(std::basic_string<charT, traits, Allocator> const& s1, charT const* s2) { return strcmp(s1.c_str(), s2); } template <typename charT, typename traits, typename Allocator> inline int strcmp(charT const* s1, std::basic_string<charT, traits, Allocator> const& s2) { return strcmp(s1, s2.c_str()); } } |
std::basic_string
クラステンプレートあるいはstd::char_traits
クラステンプレートのcompare
メンバ関数を使うという手もありますが、今回はナル終端文字列用の関数を内部的に呼び出すことで対応することにしました。
長くなってきたので、strncmp
関数相当のものは次回にまわすことにしましょう。