C++20の新機能で文字列操作を効率化:`std::basic_string`推論ガイドと`std::string_view`


C++20では、std::basic_stringテンプレートクラスに推論ガイドが導入されました。これにより、文字列リテラルやイテレータ範囲からstd::basic_stringオブジェクトをより簡単に生成できるようになりました。

本記事では、推論ガイドの仕組みと使用方法、および従来の構築方法との比較について詳しく解説します。

推論ガイドとは?

推論ガイドは、テンプレートクラスのテンプレート引数を自動的に推論するためのメカニズムです。具体的には、コンパイラは、引数に基づいてテンプレート引数を判断し、明示的に指定する必要をなくします。

std::basic_stringにおける推論ガイド

std::basic_stringテンプレートクラスには、以下の2つの推論ガイドが提供されています。

  1. イテレータ範囲からの推論ガイド

    このガイドは、イテレータ範囲を渡すことでstd::basic_stringオブジェクトを生成します。イテレータ範囲は、文字列リテラル、std::array、コンテナなどの要素範囲を表すことができます。

    例:

    const char* str = "Hello, World!";
    std::basic_string<char> s(str); // 推論ガイドにより、型 char が自動的に推論されます
    
  2. 初期化リストからの推論ガイド

    このガイドは、初期化リストを渡すことでstd::basic_stringオブジェクトを生成します。初期化リストは、文字列リテラルの要素を直接列挙することができます。

    std::basic_string<char> s {'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!'};
    

従来の構築方法との比較

推論ガイドが導入される以前は、std::basic_stringオブジェクトを生成するには、明示的にテンプレート引数を指定する必要がありました。

std::basic_string<char> s("Hello, World!", std::strlen("Hello, World!"));

推論ガイドを使用すると、コードがより簡潔になり、読みやすくなります。

推論ガイドには、以下の利点もあります。

  • コードがより汎用性が高くなります。さまざまな種類の文字列リテラルやイテレータ範囲で使用することができます。
  • コンパイルエラーを防ぎやすくなります。テンプレート引数の誤指定を防ぐことができます。

注意事項

推論ガイドを使用する場合は、以下の点に注意する必要があります。

  • 推論ガイドは、すべての状況で使用できるわけではありません。たとえば、std::string_viewオブジェクトからstd::basic_stringオブジェクトを生成するには、明示的にテンプレート引数を指定する必要があります。
  • 推論ガイドは、C++20以降のコンパイラが必要です。


#include <string>

int main() {
  const char* str = "Hello, World!";
  std::string s(str); // 推論ガイドにより、型 std::string が自動的に推論されます

  std::cout << s << std::endl;

  return 0;
}

例2:初期化リストからの推論

#include <string>

int main() {
  std::string s {'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!'};

  std::cout << s << std::endl;

  return 0;
}

例3:std::arrayからの推論

#include <string>
#include <array>

int main() {
  std::array<char, 13> arr {'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!'};
  std::string s(arr); // 推論ガイドにより、型 std::string が自動的に推論されます

  std::cout << s << std::endl;

  return 0;
}

例4:std::vectorからの推論

#include <string>
#include <vector>

int main() {
  std::vector<char> v {'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!'};
  std::string s(v.begin(), v.end()); // 推論ガイドにより、型 std::string が自動的に推論されます

  std::cout << s << std::endl;

  return 0;
}

例5:文字列リテラルからの推論

#include <string>

int main() {
  std::string s = "Hello, World!"; // 推論ガイドにより、型 std::string が自動的に推論されます

  std::cout << s << std::endl;

  return 0;
}
  • 推論ガイドは、すべての状況で使用できるわけではありません。たとえば、std::string_viewオブジェクトからstd::stringオブジェクトを生成するには、明示的にテンプレート引数を指定する必要があります。
  • 推論ガイドを使用する場合は、C++20以降のコンパイラが必要です。


ここでは、std::basic_string推論ガイドの代替方法として、以下の3つの方法をご紹介します。

明示的なテンプレート引数指定

推論ガイドが使用できない場合は、明示的にテンプレート引数を指定してstd::basic_stringオブジェクトを生成することができます。

#include <string>

int main() {
  std::basic_string<char> s("Hello, World!", std::strlen("Hello, World!"));

  std::cout << s << std::endl;

  return 0;
}

std::string_viewの使用

std::string_viewは、std::basic_stringと類似したクラスですが、メモリ管理を自分で行う必要がありません。そのため、std::basic_stringよりも軽量で効率的な場合があります。

#include <string_view>
#include <string>

int main() {
  const char* str = "Hello, World!";
  std::string_view s(str); // 推論ガイドにより、型 std::string_view が自動的に推論されます

  // std::string_view は変更できないため、コピーする必要があります
  std::string s2(s);

  std::cout << s2 << std::endl;

  return 0;
}

他の文字列操作ライブラリの使用

Boost.Stringやfmtなどの他の文字列操作ライブラリを使用することもできます。これらのライブラリは、独自の推論ガイドや文字列操作機能を提供している場合があります。

#include <boost/beast/core/buffers.hpp>
#include <boost/beast/core/string_view.hpp>

int main() {
  const char* str = "Hello, World!";
  boost::beast::string_view s(str);

  // Boost.String_view は変更できないため、コピーする必要があります
  std::string s2(s);

  std::cout << s2 << std::endl;

  return 0;
}

最適な方法の選択

使用する方法は、状況によって異なります。推論ガイドが使用できる場合は、推論ガイドを使用するのが最も簡潔で効率的な方法です。しかし、推論ガイドが使用できない場合は、上記の代替方法のいずれかを使用することができます。

  • 互換性:使用するライブラリが他のコードと互換性があることを確認する必要があります。
  • 機能性:Boost.Stringやfmtなどの他の文字列操作ライブラリは、独自の推論ガイドや文字列操作機能を提供している場合があります。
  • パフォーマンス:std::string_viewは、std::basic_stringよりも軽量で効率的な場合があります。