C++プログラミング:型推論でコードをスッキリ!std::basic_string_viewと推論ガイドの使い方


テンプレートクラスである std::basic_string_view は、コンパイラが型推論を実行できるように、推論ガイドと呼ばれる特別な機能を提供します。推論ガイドは、コンパイラが std::basic_string_view オブジェクトの型を、引数から自動的に導出できるように支援します。

推論ガイドの利点

推論ガイドを使用すると、次の利点があります。

  • テンプレートコードの汎用性の向上: 推論ガイドにより、テンプレートコードをより汎用的にすることができます。
  • コンパイルエラーの削減: 型推論により、型に関するミスを防ぎ、コンパイルエラーを減らすことができます。
  • コードの簡潔性: 明示的な型の指定が不要になり、コードが読みやすくなります。

推論ガイドの仕組み

std::basic_string_view には、2つの推論ガイドがあります。

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

    この推論ガイドは、イテレータペアを使用して std::basic_string_view オブジェクトを初期化する場合に使用されます。コンパイラは、イテレータの値型から std::basic_string_view の要素型を推論します。

    例:

    const char* str = "Hello, World!";
    std::basic_string_view view(str, str + strlen(str));
    

    この例では、コンパイラは strstr + strlen(str) の値型が char であるため、view の型を std::basic_string_view<char> と推論します。

  2. レンジからの推論ガイド

    std::string s = "Hello, World!";
    std::basic_string_view view(s);
    

    この例では、コンパイラは s の値型が char であるため、view の型を std::basic_string_view<char> と推論します。

推論ガイドは、いくつかの制約事項があります。

  • レンジは、連続範囲に対応している必要があります。
  • イテレータは、サイズ付きセンチネルに対応している必要があります。
  • イテレータまたはレンジは、連続している必要があります。


例 1: イテレータ範囲からの初期化

#include <string_view>

int main() {
  const char* str = "Hello, World!";

  // 推論ガイドを使用して std::basic_string_view<char> オブジェクトを初期化
  std::basic_string_view view(str, str + strlen(str));

  // view を使用して文字列を処理
  for (char c : view) {
    std::cout << c << " ";
  }
  std::cout << std::endl;

  return 0;
}

この例では、std::basic_string_view<char> オブジェクト viewstrstr + strlen(str) を使用して初期化されます。コンパイラは strstr + strlen(str) の値型が char であるため、view の型を自動的に推論します。

例 2: レンジからの初期化

#include <string_view>
#include <string>

int main() {
  std::string s = "Hello, World!";

  // 推論ガイドを使用して std::basic_string_view<char> オブジェクトを初期化
  std::basic_string_view view(s);

  // view を使用して文字列を処理
  for (char c : view) {
    std::cout << c << " ";
  }
  std::cout << std::endl;

  return 0;
}

この例では、std::basic_string_view<char> オブジェクト views を使用して初期化されます。コンパイラは s の値型が char であるため、view の型を自動的に推論します。

#include <string_view>

int main() {
  const char* str1 = "Hello, ";
  const char* str2 = "World!";

  // 推論ガイドは非連続イテレータをサポートしていないため、コンパイルエラーが発生
  std::basic_string_view view(str1, str2);

  return 0;
}

この例では、std::basic_string_view オブジェクト viewstr1str2 を使用して初期化しようとします。しかし、str1str2 は連続していないため、コンパイラはエラーを生成します。



明示的な型指定

最も簡単な代替方法は、明示的に型を指定することです。

#include <string_view>

int main() {
  const char* str = "Hello, World!";

  // 明示的に型を指定して std::basic_string_view<char> オブジェクトを作成
  std::basic_string_view<char> view(str, str + strlen(str));

  // view を使用して文字列を処理
  for (char c : view) {
    std::cout << c << " ";
  }
  std::cout << std::endl;

  return 0;
}

この例では、std::basic_string_view<char> オブジェクト view を明示的に型指定して作成しています。

コンストラクタの直接使用

std::basic_string_view には、さまざまなコンストラクタが用意されています。これらのコンストラクタを使用して、明示的に型を指定せずに std::basic_string_view オブジェクトを作成することができます。

#include <string_view>

int main() {
  const char* str = "Hello, World!";

  // std::basic_string_view<char> オブジェクトを直接作成
  std::basic_string_view view(str);

  // view を使用して文字列を処理
  for (char c : view) {
    std::cout << c << " ";
  }
  std::cout << std::endl;

  return 0;
}

この例では、std::basic_string_view<char> オブジェクト viewstd::basic_string_view コンストラクタを使用して直接作成しています。

std::basic_string_view 以外にも、型推論をサポートするテンプレートクラスがいくつかあります。これらのクラスを使用して、std::basic_string_view オブジェクトを作成することができます。

  • std::span: C++21 で導入された、固定サイズの連続メモリ領域を表すテンプレートクラスです。
  • std::string_view: C++20 で導入された std::basic_string_view と同様のクラスですが、std::string オブジェクトを直接参照できます。

std::basic_string_view 推論ガイドは便利な機能ですが、制約事項があります。推論ガイドを使用できない場合、または別の方法で std::basic_string_view オブジェクトを作成したい場合は、上記の代替方法を使用することができます。