C++でC風ライブラリを作る(文字探索編)

高木です。こんにちは。
文字列処理関数が続いています。
 こうやって見ると結構な量がありますね。
 地道な作業ですが、徹底的にやりたいと思います(ブログのネタにも困りませんからね)。
 
今回は文字探索関数です。
 Cの文字列中の文字探索関数には、大きく分けて2種類あります。
ひとつは、文字列の先頭から末尾に向けて探索するstrchr関数です。
 もうひとつは、逆に文字列の末尾から文字列の先頭に向けて探索する関数です。
strchr関数やstrrchr関数はchar型の文字列のためのものですが、wchar_t型の文字列のためのwcschr関数とwcsrchr関数もあります。
 今回のライブラリでは、いつものようにchar16_t型などの文字列にも対応します。
Cのstrchr関数やstrrchr関数はchar const*型を受け取りchar*型を返します。
 多重定義が可能なC++では、char const*型を受け取りchar const*を返すものと、char*型を受け取りchar*を返すものが用意されています。
第2引数はint型ですが、昔は関数原型(プロトタイプ)無しでも呼び出せる必要があったからではないかと思います。
 今となっては、またC++では意味がないので、素直にchar型を受け取るようにしたほうがいいでしょう。
 getc関数などint型を返す関数との相性を考えるとint型にするのも悪くないんでしょうけど。
それでは実装を見ていきましょう。
 まずは素直にテンプレートを使って実装します。
| 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>   inline charT* strchr(charT* s, charT c)   {     while (auto cc = *s)     {       if (cc == c)         return s;       ++s;     }     return nullptr;   }   template <typename charT>   inline charT const* strchr(charT const* s, charT c)   {     return strchr(const_cast<charT*>(s), c);   } } | 
そして、char型やwchar_t型の文字列のための関数を多重定義します。
 これもいつも通りですね。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | namespace cloverfield {   inline char* strchr(char* s, char c)   {     return std::strchr(s, c);   }   inline char const* strchr(char const* s, char c)   {     return std::strchr(s, c);   }   inline wchar_t* strchr(wchar_t* s, wchar_t c)   {     return std::wcschr(s, c);   }   inline wchar_t const* strchr(wchar_t const* s, wchar_t c)   {     return std::wcschr(s, c);   } } | 
最後にstd::basic_stringクラステンプレートのための関数を定義しましょう。
| 1 2 3 4 5 6 7 8 | namespace cloverfield {   template <typename charT, typename traits, typename Allocator>   inline charT const* strchr(std::basic_string<charT, traits, Allocator> const& s, charT c)   {     return strchr(s.c_str(), c);   } } | 
このライブラリはC++11を使うことにしているので、std::basic_stringクラステンプレート版はconst修飾されていない文字列を返す版はあえて定義していません。
C++17では、const修飾のないポインタを返すdataメンバ関数もあるのですが、C++11の範囲では無理矢理const_castでconst修飾を外さないといけませんし、そうしたポインタを介して文字を上書きすると未定義の動作になるのでやめておきます。
次回はstrrchr関数を定義することにします。
 ほとんど変わらないんですけどね。

