C++でC風ライブラリを作る(文字列コピー編2)
高木です。おはようございます。
この前の週末はTOPPERSカンファレンス2019のレポートが立て続けに投稿されたこともあって、私の出番はすっかりなくなってしまいました。
どうせ遅れたのであれば遅れついでということで、水曜日に予約投稿することにします。
水曜日の夜は馬詰がライブに行くとのことなので、なるべく負担を軽減しようと考えてのことです。
ライブのレポートは翌日にでもしてくれることでしょう。
さて、今回は前回予告したように、文字列コピーを行うstrcpy
関数とstrncpy
関数をstd::basic_string
クラステンプレートに対応することにします。
といっても、やることは至極単純かつ退屈な内容です。
どの関数も、コピー元とコピー先の2つの文字列を引数にとります。
片方は単なる格納先に過ぎないので、まともな文字列はコピー元だけということになるかもしれませんが、ここはあまり深くは追求しないことにしましょう。
前回は、strcpy
関数は大別して2種類のものを多重定義しました。
ひとつはコピー先の配列とコピー元の文字列の2引数のもの、もうひとつはコピー先へのポインタとコピー元の文字列、そしてコピー先のサイズの3引数のものです。
2種類のstrcpy
関数と1種類のstrncpy
関数を、引数の型の組み合わせ分だけ多重定義することになります。
今回もこの流儀を踏襲していくことにします。
それでは早速コードを見ていきましょう。
まずは2つのコピー元、コピー先ともにstd::basic_string
クラステンプレートの場合です。
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, typename traits, typename Allocator1, typename Allocator2> inline std::basic_string<charT, traits, Allocator1>& strcpy(std::basic_string<charT, traits, Allocator1>& s1, std::basic_string<charT, traits, Allocator2> const& s2) { return s1.assign(s2); } template <typename charT, typename traits, typename Allocator1, typename Allocator2> inline std::basic_string<charT, traits, Allocator1>& strcpy(std::basic_string<charT, traits, Allocator1>& s1, std::basic_string<charT, traits, Allocator2> const& s2, std::size_t n) { return s1.assign(s2, 0, n); } template <typename charT, typename traits, typename Allocator1, typename Allocator2> inline std::basic_string<charT, traits, Allocator1>& strncpy(std::basic_string<charT, traits, Allocator1>& s1, std::basic_string<charT, traits, Allocator2> const& s2, std::size_t n) { std::string ss(n, charT(0)); std::copy_n(s2.begin(), std::min(s2.size(), n), ss.begin()); s1.swap(ss); return s1; } } |
続いて、コピー先のみがstd::basic_string
クラステンプレートの場合です。
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, typename traits, typename Allocator> inline std::basic_string<charT, traits, Allocator>& strcpy(std::basic_string<charT, traits, Allocator>& s1, charT const* s2) { return s1.assign(s2); } template <typename charT, typename traits, typename Allocator> inline std::basic_string<charT, traits, Allocator>& strcpy(std::basic_string<charT, traits, Allocator>& s1, charT const* s2, std::size_t n) { return s1.assign(s2, 0, n); } template <typename charT, typename traits, typename Allocator> inline std::basic_string<charT, traits, Allocator>& strncpy(std::basic_string<charT, traits, Allocator>& s1, charT const* s2, std::size_t n) { std::string ss(n, charT(0)); std::copy_n(s2, std::min(strlen(s2), n), ss.begin()); s1.swap(ss); return s1; } } |
今度は逆に、コピー元のみが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, std::size_t N, typename traits, typename Allocator> inline charT* strcpy(charT (&s1)[N], std::basic_string<charT, traits, Allocator> const& s2) { return strcpy(s1, s2.c_str()); } template <typename charT, typename traits, typename Allocator> inline charT* strcpy(charT* s1, std::basic_string<charT, traits, Allocator> const& s2, std::size_t n) { return strcpy(s1, s2.c_str(), n); } template <typename charT, typename traits, typename Allocator> inline charT* strncpy(charT* s1, std::basic_string<charT, traits, Allocator> const& s2, std::size_t n) { return strncpy(s1, s2.c_str(), n); } } |
最初に述べたように、今回は単純な関数の多重定義を繰り返すだけのたいくつな内容です。
ソースコードの説明はあえて行いませんし、コメントも一切入っていませんが、見ればわかるというものです。