大阪市中央区 システムソフトウェア開発会社

営業時間:平日09:15〜18:15
MENU

C++でC風ライブラリを作る(文字列コピー編2)

著者:高木信尚
公開日:2019/06/19
最終更新日:2019/06/17
カテゴリー:技術情報

高木です。おはようございます。

この前の週末はTOPPERSカンファレンス2019のレポートが立て続けに投稿されたこともあって、私の出番はすっかりなくなってしまいました。
どうせ遅れたのであれば遅れついでということで、水曜日に予約投稿することにします。
水曜日の夜は馬詰がライブに行くとのことなので、なるべく負担を軽減しようと考えてのことです。
ライブのレポートは翌日にでもしてくれることでしょう。

さて、今回は前回予告したように、文字列コピーを行うstrcpy関数とstrncpy関数をstd::basic_stringクラステンプレートに対応することにします。
といっても、やることは至極単純かつ退屈な内容です。

どの関数も、コピー元とコピー先の2つの文字列を引数にとります。
片方は単なる格納先に過ぎないので、まともな文字列はコピー元だけということになるかもしれませんが、ここはあまり深くは追求しないことにしましょう。

前回は、strcpy関数は大別して2種類のものを多重定義しました。
ひとつはコピー先の配列とコピー元の文字列の2引数のもの、もうひとつはコピー先へのポインタとコピー元の文字列、そしてコピー先のサイズの3引数のものです。
2種類のstrcpy関数と1種類のstrncpy関数を、引数の型の組み合わせ分だけ多重定義することになります。
今回もこの流儀を踏襲していくことにします。

それでは早速コードを見ていきましょう。

まずは2つのコピー元、コピー先ともにstd::basic_stringクラステンプレートの場合です。

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クラステンプレートの場合です。

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クラステンプレートの場合です。

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);
  }
}

最初に述べたように、今回は単純な関数の多重定義を繰り返すだけのたいくつな内容です。
ソースコードの説明はあえて行いませんし、コメントも一切入っていませんが、見ればわかるというものです。

    上に戻る