C++ 生成コードガイド

Protocol Buffer コンパイラが、与えられたプロトコル定義に対して、どのような C++ コードを生成するかを正確に記述します。

proto2、proto3、およびエディションによって生成されるコードの違いを強調しています。これらの違いは、このドキュメントで説明されている生成コードにあり、すべてのバージョンで同じである基本メッセージクラス/インターフェースにはありません。このドキュメントを読む前に、proto2 言語ガイドproto3 言語ガイド、またはエディション 2023 言語ガイドを読む必要があります。

コンパイラの呼び出し

Protocol Buffer コンパイラは、--cpp_out= コマンドラインフラグを指定して起動すると、C++ 出力を生成します。--cpp_out= オプションのパラメータは、コンパイラが C++ 出力を書き込むディレクトリです。コンパイラは、各 .proto ファイル入力に対して、ヘッダーファイルと実装ファイルを生成します。出力ファイルの名前は、.proto ファイルの名前を取り、2つの変更を加えることによって計算されます

  • 拡張子 (.proto) は、それぞれヘッダーファイルの場合は .pb.h に、実装ファイルの場合は .pb.cc に置き換えられます。
  • プロトパス (--proto_path= または -I コマンドラインフラグで指定) は、出力パス (--cpp_out= フラグで指定) に置き換えられます。

例えば、次のようにコンパイラを呼び出すとします。

protoc --proto_path=src --cpp_out=build/gen src/foo.proto src/bar/baz.proto

コンパイラは src/foo.protosrc/bar/baz.proto のファイルを読み込み、build/gen/foo.pb.hbuild/gen/foo.pb.ccbuild/gen/bar/baz.pb.hbuild/gen/bar/baz.pb.cc の4つの出力ファイルを生成します。コンパイラは必要に応じてディレクトリ build/gen/bar を自動的に作成しますが、buildbuild/gen は作成しません。これらはすでに存在している必要があります。

パッケージ

.proto ファイルに package 宣言が含まれている場合、ファイルの内容全体は対応する C++ 名前空間に配置されます。たとえば、次の package 宣言が与えられた場合

package foo.bar;

ファイル内のすべての宣言は foo::bar 名前空間内に存在します。

メッセージ

単純なメッセージ宣言を考えます。

message Foo {}

Protocol Buffer コンパイラは、google::protobuf::Message から公開継承する Foo というクラスを生成します。このクラスは具象クラスであり、未実装の純粋仮想メソッドは残されていません。Message の仮想メソッドのうち、純粋仮想ではないメソッドは、最適化モードに応じて、Foo によってオーバーライドされる場合とされない場合があります。デフォルトでは、Foo は最高の速度のためにすべてのメソッドの特殊なバージョンを実装します。ただし、.proto ファイルに次の行が含まれている場合

option optimize_for = CODE_SIZE;

Foo は、機能するために必要な最小限のメソッドセットのみをオーバーライドし、残りはリフレクションベースの実装に依存します。これにより、生成されるコードのサイズが大幅に削減されますが、パフォーマンスも低下します。あるいは、.proto ファイルに次が含まれている場合

option optimize_for = LITE_RUNTIME;

Foo にはすべてのメソッドの高速実装が含まれますが、Message のメソッドの一部のみを含むgoogle::protobuf::MessageLiteインターフェースを実装します。特に、記述子やリフレクションをサポートしません。ただし、このモードでは、生成されたコードは libprotobuf.so (Windows では libprotobuf.lib) の代わりに libprotobuf-lite.so (Windows では libprotobuf-lite.lib) にリンクするだけで済みます。「lite」ライブラリは完全なライブラリよりもはるかに小さく、携帯電話などのリソース制約のあるシステムに適しています。

独自の Foo サブクラスを作成してはなりません。このクラスをサブクラス化して仮想メソッドをオーバーライドすると、パフォーマンスを向上させるために多くの生成されたメソッド呼び出しが非仮想化されるため、オーバーライドが無視される可能性があります。

Message インターフェースは、バイナリ文字列からの解析やバイナリ文字列へのシリアル化を含む、メッセージ全体をチェック、操作、読み書きできるメソッドを定義します。

  • bool ParseFromString(::absl::string_view data): 指定されたシリアル化されたバイナリ文字列 (ワイヤフォーマットとも呼ばれます) からメッセージを解析します。
  • bool SerializeToString(string* output) const: 指定されたメッセージをバイナリ文字列にシリアル化します。
  • string DebugString(): プロトの text_format 表現を示す文字列を返します (デバッグ目的でのみ使用してください)。

これらのメソッドに加えて、Foo クラスは以下のメソッドを定義します

  • Foo(): デフォルトコンストラクタ。
  • ~Foo(): デフォルトデストラクタ。
  • Foo(const Foo& other): コピーコンストラクタ。
  • Foo(Foo&& other): ムーブコンストラクタ。
  • Foo& operator=(const Foo& other): 代入演算子。
  • Foo& operator=(Foo&& other): ムーブ代入演算子。
  • void Swap(Foo* other): 他のメッセージと内容をスワップします。
  • const UnknownFieldSet& unknown_fields() const: このメッセージを解析中に遭遇した未知のフィールドのセットを返します。.proto ファイルで option optimize_for = LITE_RUNTIME が指定されている場合、戻り値の型は std::string& に変更されます。
  • UnknownFieldSet* mutable_unknown_fields(): このメッセージを解析中に遭遇した変更可能な未知のフィールドのセットへのポインタを返します。.proto ファイルで option optimize_for = LITE_RUNTIME が指定されている場合、戻り値の型は std::string* に変更されます。

注:コピーコンストラクタと代入演算子は、メッセージデータのディープコピーを実行します。これにより、各メッセージオブジェクトが独自のデータのコピーを所有および管理し、二重解放や解放後の使用エラーなどの問題を防止します。この動作は、std::vectorのようなデータを所有するオブジェクトの標準的なC++プラクティスと一貫しています。異なるコピーセマンティクス(例えばJavaScriptやTypeScriptのようにシャローコピーがより一般的である場合)を持つ言語から来る開発者にとって、コピーされたメッセージへの変更は元のメッセージに影響せず、またその逆も同様であることに注意することが重要です。

このクラスは、以下の静的メソッドも定義します

  • static const Descriptor* descriptor(): 型の記述子を返します。これには、その型に関する情報(どのようなフィールドを持ち、その型が何であるかなど)が含まれます。これは、プログラム的にフィールドを検査するためにリフレクションとともに使用できます。
  • static const Foo& default_instance(): 新しく構築された Foo のインスタンスと同一の Foo の定数シングルトンインスタンスを返します (したがって、すべての単一フィールドは設定されておらず、すべての繰り返しフィールドは空です)。メッセージのデフォルトインスタンスは、その New() メソッドを呼び出すことによってファクトリとして使用できることに注意してください。

生成されるファイル名

予約語には、生成された出力でアンダースコアが追加されます。

たとえば、次の proto3 定義構文は

message MyMessage {
  string false = 1;
  string myFalse = 2;
}

次の部分的な出力を生成します

  void clear_false_() ;
  const std::string& false_() const;
  void set_false_(Arg_&& arg, Args_... args);
  std::string* mutable_false_();
  PROTOBUF_NODISCARD std::string* release_false_();
  void set_allocated_false_(std::string* ptr);

  void clear_myfalse() ;
  const std::string& myfalse() const;
  void set_myfalse(Arg_&& arg, Args_... args);
  std::string* mutable_myfalse();
  PROTOBUF_NODISCARD std::string* release_myfalse();
  void set_allocated_myfalse(std::string* ptr);

ネストされた型

メッセージは別のメッセージ内で宣言できます。例:

message Foo {
  message Bar {}
}

この場合、コンパイラは2つのクラス、FooFoo_Bar を生成します。さらに、コンパイラは Foo の内部に次のような typedef を生成します

typedef Foo_Bar Bar;

これは、ネストされた型のクラスを、ネストされたクラス Foo::Bar のように使用できることを意味します。ただし、C++ ではネストされた型を前方宣言できないことに注意してください。別のファイルで Bar を前方宣言してその宣言を使用したい場合は、それを Foo_Bar として識別する必要があります。

フィールド

前のセクションで説明したメソッドに加えて、プロトコルバッファコンパイラは、.proto ファイルのメッセージ内に定義された各フィールドに対して、一連のアクセサメソッドを生成します。これらのメソッドは、has_foo()clear_foo() のように、小文字/スネークケースです。

アクセサメソッドと同様に、コンパイラは各フィールドに対してそのフィールド番号を含む整数定数を生成します。定数名は文字 k、フィールド名をキャメルケースに変換したもの、および FieldNumber です。たとえば、フィールド optional int32 foo_bar = 5; が与えられた場合、コンパイラは定数 static const int kFooBarFieldNumber = 5; を生成します。

const 参照を返すフィールドアクセサの場合、その参照は、メッセージに対して次に変更アクセスが行われたときに無効になる可能性があります。これには、任意のフィールドの非 const アクセサの呼び出し、Message から継承された任意の非 const メソッドの呼び出し、またはその他の方法(たとえば、メッセージを Swap() の引数として使用するなど)によるメッセージの変更が含まれます。同様に、返される参照のアドレスは、その間にメッセージに対して変更アクセスが行われなかった場合にのみ、アクセサの異なる呼び出し間で同じであることが保証されます。

ポインタを返すフィールドアクセサの場合、そのポインタは、メッセージに対して次に変更または非変更アクセスが行われたときに無効になる可能性があります。これには、const かどうかにかかわらず、任意のフィールドのアクセサの呼び出し、Message から継承された任意のメソッドの呼び出し、またはその他の方法(たとえば、コピーコンストラクタを使用してメッセージをコピーするなど)によるメッセージへのアクセスが含まれます。同様に、返されるポインタの値は、アクセサの2つの異なる呼び出し間で同じであることが決して保証されません。

明示的な存在を持つ数値フィールド

明示的な存在を持つ数値フィールドのフィールド定義の場合

int32 foo = 1;

コンパイラは以下のアクセサメソッドを生成します

  • bool has_foo() const: フィールドが設定されている場合に true を返します。
  • int32_t foo() const: フィールドの現在の値を返します。フィールドが設定されていない場合、デフォルト値を返します。
  • void set_foo(::int32_t value): フィールドの値を設定します。これを呼び出すと、has_foo()true を返し、foo()value を返します。
  • void clear_foo(): フィールドの値をクリアします。これを呼び出すと、has_foo()false を返し、foo() はデフォルト値を返します。

その他の数値フィールド型 (bool を含む) の場合、int32_t は、スカラ値型のテーブルに従って対応する C++ 型に置き換えられます。

暗黙的な存在を持つ数値フィールド

暗黙的な存在を持つ数値フィールドのフィールド定義の場合

int32 foo = 1;

コンパイラは以下のアクセサメソッドを生成します

  • ::int32_t foo() const: フィールドの現在の値を返します。フィールドが設定されていない場合、0 を返します。
  • void set_foo(::int32_t value): フィールドの値を設定します。これを呼び出すと、foo()value を返します。
  • void clear_foo(): フィールドの値をクリアします。これを呼び出すと、foo() は 0 を返します。

その他の数値フィールド型 (bool を含む) の場合、int32_t は、スカラ値型のテーブルに従って対応する C++ 型に置き換えられます。

明示的な存在を持つ文字列/バイトフィールド

注: Edition 2023 以降、features.(pb.cpp).string_typeVIEW に設定されている場合、string_view API が代わりに生成されます。

明示的な存在を持つこれらのフィールド定義の場合

string foo = 1;
bytes foo = 2;

コンパイラは以下のアクセサメソッドを生成します

  • bool has_foo() const: フィールドが設定されている場合に true を返します。

  • const string& foo() const: フィールドの現在の値を返します。フィールドが設定されていない場合、デフォルト値を返します。

  • void set_foo(...): フィールドの値を設定します。これを呼び出すと、has_foo()true を返し、foo()value のコピーを返します。

  • string* mutable_foo(): フィールドの値を格納する変更可能な string オブジェクトへのポインタを返します。呼び出し前にフィールドが設定されていなかった場合、返される文字列は空になります (デフォルト値ではありません)。これを呼び出した後、has_foo()true を返し、foo() は指定された文字列に書き込まれた任意の値を返します。

    注: このメソッドは新しい string_view API では削除されます。

  • void clear_foo(): フィールドの値をクリアします。これを呼び出すと、has_foo()false を返し、foo() はデフォルト値を返します。

  • void set_allocated_foo(string* value): string オブジェクトをフィールドに設定し、以前のフィールド値が存在する場合は解放します。string ポインタが NULL でない場合、メッセージは割り当てられた string オブジェクトの所有権を取得し、has_foo()true を返します。メッセージは割り当てられた string オブジェクトをいつでも削除できるため、オブジェクトへの参照は無効になる可能性があります。それ以外の場合、valueNULL の場合、動作は clear_foo() を呼び出すのと同じです。

  • string* release_foo(): フィールドの所有権を解放し、string オブジェクトのポインタを返します。これを呼び出した後、呼び出し元は割り当てられた string オブジェクトの所有権を取得し、has_foo()false を返し、foo() はデフォルト値を返します。

暗黙的な存在を持つ文字列/バイトフィールド

注: Edition 2023 以降、features.(pb.cpp).string_typeVIEW に設定されている場合、string_view API が代わりに生成されます。

暗黙的な存在を持つこれらのフィールド定義の場合

string foo = 1 [features.field_presence = IMPLICIT];
bytes foo = 1 [features.field_presence = IMPLICIT];

コンパイラは以下のアクセサメソッドを生成します

  • const string& foo() const: フィールドの現在の値を返します。フィールドが設定されていない場合、空の文字列/空のバイトを返します。
  • void set_foo(Arg_&& arg, Args_... args): フィールドの値を設定します。これを呼び出すと、foo()value のコピーを返します。
  • string* mutable_foo(): フィールドの値を格納する変更可能な string オブジェクトへのポインタを返します。呼び出し前にフィールドが設定されていなかった場合、返される文字列は空になります。これを呼び出した後、foo() は指定された文字列に書き込まれた任意の値を返します。
  • void clear_foo(): フィールドの値をクリアします。これを呼び出すと、foo() は空の文字列/空のバイトを返します。
  • void set_allocated_foo(string* value): string オブジェクトをフィールドに設定し、以前のフィールド値が存在する場合は解放します。string ポインタが NULL でない場合、メッセージは割り当てられた string オブジェクトの所有権を取得します。メッセージは割り当てられた string オブジェクトをいつでも削除できるため、オブジェクトへの参照は無効になる可能性があります。それ以外の場合、valueNULL の場合、動作は clear_foo() を呼び出すのと同じです。
  • string* release_foo(): フィールドの所有権を解放し、string オブジェクトのポインタを返します。これを呼び出した後、呼び出し元は割り当てられた string オブジェクトの所有権を取得し、foo() は空の文字列/空のバイトを返します。

Cord サポート付き単一バイトフィールド

v23.0 では、単一の bytes フィールド (oneof フィールドを含む) に対してabsl::Cord のサポートが追加されました。単一の stringrepeated string、および repeated bytes フィールドは Cord の使用をサポートしていません。

単一の bytes フィールドを absl::Cord を使用してデータを格納するように設定するには、次の構文を使用します

// edition (default settings)
bytes foo = 25 [ctype=CORD];
bytes foo = 26 [ctype=CORD, features.field_presence = IMPLICIT];

cord の使用は、repeated bytes フィールドでは利用できません。Protoc は、これらのフィールドの [ctype=CORD] 設定を無視します。

コンパイラは以下のアクセサメソッドを生成します

  • const ::absl::Cord& foo() const: フィールドの現在の値を返します。フィールドが設定されていない場合、空の Cord (proto3) またはデフォルト値 (proto2 および editions) を返します。
  • void set_foo(const ::absl::Cord& value): フィールドの値を設定します。これを呼び出すと、foo()value を返します。
  • void set_foo(::absl::string_view value): フィールドの値を設定します。これを呼び出すと、foo()valueabsl::Cord として返します。
  • void clear_foo(): フィールドの値をクリアします。これを呼び出すと、foo() は空の Cord (proto3) またはデフォルト値 (proto2 および editions) を返します。
  • bool has_foo(): フィールドが設定されている場合に true を返します。proto3 の optional フィールドおよび editions の明示的な存在フィールドにのみ適用されます。

明示的な存在を持つEnumフィールド

enum型が与えられた場合

enum Bar {
  BAR_UNSPECIFIED = 0;
  BAR_VALUE = 1;
  BAR_OTHER_VALUE = 2;
}

明示的な存在を持つこのフィールド定義の場合

Bar bar = 1;

コンパイラは以下のアクセサメソッドを生成します

  • bool has_bar() const: フィールドが設定されている場合に true を返します。
  • Bar bar() const: フィールドの現在の値を返します。フィールドが設定されていない場合、デフォルト値を返します。
  • void set_bar(Bar value): フィールドの値を設定します。これを呼び出すと、has_bar()true を返し、bar()value を返します。デバッグモード (つまり、NDEBUG が定義されていない) では、valueBar に定義されている値のいずれにも一致しない場合、このメソッドはプロセスをアボートします。
  • void clear_bar(): フィールドの値をクリアします。これを呼び出すと、has_bar()false を返し、bar() はデフォルト値を返します。

暗黙的な存在を持つEnumフィールド

enum型が与えられた場合

enum Bar {
  BAR_UNSPECIFIED = 0;
  BAR_VALUE = 1;
  BAR_OTHER_VALUE = 2;
}

暗黙的な存在を持つこのフィールド定義の場合

Bar bar = 1;

コンパイラは以下のアクセサメソッドを生成します

  • Bar bar() const: フィールドの現在の値を返します。フィールドが設定されていない場合、デフォルト値 (0) を返します。
  • void set_bar(Bar value): フィールドの値を設定します。これを呼び出すと、bar()value を返します。
  • void clear_bar(): フィールドの値をクリアします。これを呼び出すと、bar() はデフォルト値を返します。

明示的な存在を持つ埋め込みメッセージフィールド

メッセージ型を考えると:

message Bar {}

明示的な存在を持つこのフィールド定義の場合

Bar bar = 1;

コンパイラは以下のアクセサメソッドを生成します

  • bool has_bar() const: フィールドが設定されている場合に true を返します。
  • const Bar& bar() const: フィールドの現在の値を返します。フィールドが設定されていない場合、フィールドが設定されていない Bar を返します (Bar::default_instance() の可能性があります)。
  • Bar* mutable_bar(): フィールドの値を格納する変更可能な Bar オブジェクトへのポインタを返します。呼び出し前にフィールドが設定されていなかった場合、返される Bar はどのフィールドも設定されていません (つまり、新しく割り当てられた Bar と同一になります)。これを呼び出した後、has_bar()true を返し、bar()Bar の同じインスタンスへの参照を返します。
  • void clear_bar(): フィールドの値をクリアします。これを呼び出すと、has_bar()false を返し、bar() はデフォルト値を返します。
  • void set_allocated_bar(Bar* value): Bar オブジェクトをフィールドに設定し、以前のフィールド値が存在する場合は解放します。Bar ポインタが NULL でない場合、メッセージは割り当てられた Bar オブジェクトの所有権を取得し、has_bar()true を返します。それ以外の場合、BarNULL の場合、動作は clear_bar() を呼び出すのと同じです。
  • Bar* release_bar(): フィールドの所有権を解放し、Bar オブジェクトのポインタを返します。これを呼び出した後、呼び出し元は割り当てられた Bar オブジェクトの所有権を取得し、has_bar()false を返し、bar() はデフォルト値を返します。

繰り返し数値フィールド

このフィールド定義について:

repeated int32 foo = 1;

コンパイラは以下のアクセサメソッドを生成します

  • int foo_size() const: 現在フィールドにある要素の数を返します。空のセットをチェックするには、このメソッドの代わりに、基になる RepeatedFieldempty()メソッドの使用を検討してください。
  • int32_t foo(int index) const: 指定された0ベースのインデックスの要素を返します。このメソッドを [0, foo_size()) の範囲外のインデックスで呼び出すと未定義の動作になります。
  • void set_foo(int index, int32_t value): 指定された0ベースのインデックスの要素の値を設定します。
  • void add_foo(int32_t value): 指定された値を持つ新しい要素をフィールドの末尾に追加します。
  • void clear_foo(): フィールドからすべての要素を削除します。これを呼び出すと、foo_size() はゼロを返します。
  • const RepeatedField<int32_t>& foo() const: フィールドの要素を格納する基になるRepeatedFieldを返します。このコンテナクラスは、STLのようなイテレータやその他のメソッドを提供します。
  • RepeatedField<int32_t>* mutable_foo(): フィールドの要素を格納する基になる変更可能な RepeatedField へのポインタを返します。このコンテナクラスは、STLのようなイテレータやその他のメソッドを提供します。

その他の数値フィールド型 (bool を含む) の場合、int32_t は、スカラ値型のテーブルに従って対応する C++ 型に置き換えられます。

繰り返し文字列フィールド

注: Edition 2023 以降、features.(pb.cpp).string_typeVIEW に設定されている場合、string_view API が代わりに生成されます。

これらのフィールド定義のいずれかの場合

repeated string foo = 1;
repeated bytes foo = 1;

コンパイラは以下のアクセサメソッドを生成します

  • int foo_size() const: 現在フィールドにある要素の数を返します。空のセットをチェックするには、このメソッドの代わりに、基になる RepeatedFieldempty()メソッドの使用を検討してください。
  • const string& foo(int index) const: 指定された0ベースのインデックスの要素を返します。このメソッドを [0, foo_size()-1] の範囲外のインデックスで呼び出すと未定義の動作になります。
  • void set_foo(int index, ::absl::string_view value): 指定された0ベースのインデックスの要素の値を設定します。
  • void set_foo(int index, const string& value): 指定された0ベースのインデックスの要素の値を設定します。
  • void set_foo(int index, string&& value): 渡された文字列から移動して、指定されたゼロベースのインデックスにある要素の値を設定します。
  • void set_foo(int index, const char* value): Cスタイルのヌル終端文字列を使用して、指定されたゼロベースのインデックスにある要素の値を設定します。
  • void set_foo(int index, const char* value, int size): ヌルターミネータバイトを探して決定するのではなく、明示的に指定されたサイズの C スタイル文字列を使用して、指定されたゼロベースのインデックスの要素の値を設定します。
  • string* mutable_foo(int index): 指定された0ベースのインデックスの要素の値を格納する変更可能な string オブジェクトへのポインタを返します。このメソッドを [0, foo_size()) の範囲外のインデックスで呼び出すと未定義の動作になります。
  • void add_foo(::absl::string_view value): 指定された値を持つ新しい要素をフィールドの末尾に追加します。
  • void add_foo(const string& value): 指定された値を持つ新しい要素をフィールドの末尾に追加します。
  • void add_foo(string&& value): 渡された文字列から移動して、新しい要素をフィールドの末尾に追加します。
  • void add_foo(const char* value): Cスタイルのヌル終端文字列を使用して、新しい要素をフィールドの末尾に追加します。
  • void add_foo(const char* value, int size): ヌルターミネータバイトを探して決定するのではなく、明示的に指定されたサイズの文字列を使用して、新しい要素をフィールドの末尾に追加します。
  • string* add_foo(): 新しい空の文字列要素をフィールドの末尾に追加し、それへのポインタを返します。
  • void clear_foo(): フィールドからすべての要素を削除します。これを呼び出すと、foo_size() はゼロを返します。
  • const RepeatedPtrField<string>& foo() const: フィールドの要素を格納する基になるRepeatedPtrFieldを返します。このコンテナクラスは、STLのようなイテレータやその他のメソッドを提供します。
  • RepeatedPtrField<string>* mutable_foo(): フィールドの要素を格納する基になる変更可能な RepeatedPtrField へのポインタを返します。このコンテナクラスは、STLのようなイテレータやその他のメソッドを提供します。

繰り返しEnumフィールド

enum型が与えられた場合

enum Bar {
  BAR_UNSPECIFIED = 0;
  BAR_VALUE = 1;
  BAR_OTHER_VALUE = 2;
}

このフィールド定義について:

repeated Bar bar = 1;

コンパイラは以下のアクセサメソッドを生成します

  • int bar_size() const: 現在フィールドにある要素の数を返します。空のセットをチェックするには、このメソッドの代わりに、基になる RepeatedFieldempty()メソッドの使用を検討してください。
  • Bar bar(int index) const: 指定された0ベースのインデックスの要素を返します。このメソッドを [0, bar_size()) の範囲外のインデックスで呼び出すと未定義の動作になります。
  • void set_bar(int index, Bar value): 指定された0ベースのインデックスの要素の値を設定します。デバッグモード (つまり、NDEBUG が定義されていない) では、valueBar に定義されている値のいずれにも一致せず、それがクローズドな列挙型である場合、このメソッドはプロセスをアボートします。
  • void add_bar(Bar value): 指定された値を持つ新しい要素をフィールドの末尾に追加します。デバッグモード (つまり、NDEBUG が定義されていない) では、valueBar に定義されている値のいずれにも一致しない場合、このメソッドはプロセスをアボートします。
  • void clear_bar(): フィールドからすべての要素を削除します。これを呼び出すと、bar_size() はゼロを返します。
  • const RepeatedField<int>& bar() const: フィールドの要素を格納する基になるRepeatedFieldを返します。このコンテナクラスは、STLのようなイテレータやその他のメソッドを提供します。
  • RepeatedField<int>* mutable_bar(): フィールドの要素を格納する基になる変更可能な RepeatedField へのポインタを返します。このコンテナクラスは、STLのようなイテレータやその他のメソッドを提供します。

リピート埋め込みメッセージフィールド

メッセージ型を考えると:

message Bar {}

このフィールド定義の場合

repeated Bar bar = 1;

コンパイラは以下のアクセサメソッドを生成します

  • int bar_size() const: 現在フィールドにある要素の数を返します。空のセットをチェックするには、このメソッドの代わりに、基になる RepeatedFieldempty()メソッドの使用を検討してください。
  • const Bar& bar(int index) const: 指定されたゼロベースのインデックスにある要素を返します。このメソッドを [0, bar_size()) の範囲外のインデックスで呼び出すと、未定義の動作になります。
  • Bar* mutable_bar(int index): 指定されたゼロベースのインデックスにある要素の値を格納する変更可能な Bar オブジェクトへのポインタを返します。このメソッドを [0, bar_size()) の範囲外のインデックスで呼び出すと、未定義の動作になります。
  • Bar* add_bar(): フィールドの末尾に新しい要素を追加し、それへのポインタを返します。返される Bar は変更可能で、どのフィールドも設定されていません (つまり、新しく割り当てられた Bar と同一になります)。
  • void clear_bar(): フィールドからすべての要素を削除します。これを呼び出すと、bar_size() はゼロを返します。
  • const RepeatedPtrField<Bar>& bar() const: フィールドの要素を格納する基になるRepeatedPtrFieldを返します。このコンテナクラスは、STLのようなイテレータやその他のメソッドを提供します。
  • RepeatedPtrField<Bar>* mutable_bar(): フィールドの要素を格納する基になる変更可能な RepeatedPtrField へのポインタを返します。このコンテナクラスは、STLのようなイテレータやその他のメソッドを提供します。

Oneof 数値フィールド

このoneofフィールド定義の場合

oneof example_name {
    int32 foo = 1;
    ...
}

コンパイラは以下のアクセサメソッドを生成します

  • bool has_foo() const: oneof ケースが kFoo の場合に true を返します。
  • int32 foo() const: oneof ケースが kFoo の場合、フィールドの現在の値を返します。それ以外の場合、デフォルト値を返します。
  • void set_foo(int32 value):
    • 同じ oneof 内の他の oneof フィールドが設定されている場合、clear_example_name() を呼び出します。
    • このフィールドの値を設定し、oneof ケースを kFoo に設定します。
    • has_foo() は true を返し、foo()value を返し、example_name_case()kFoo を返します。
  • void clear_foo():
    • oneof ケースが kFoo でない場合、何も変更されません。
    • oneof ケースが kFoo の場合、フィールドの値と oneof ケースをクリアします。has_foo()false を返し、foo() はデフォルト値を返し、example_name_case()EXAMPLE_NAME_NOT_SET を返します。

その他の数値フィールド型 (bool を含む) の場合、int32_t は、スカラ値型のテーブルに従って対応する C++ 型に置き換えられます。

Oneof 文字列フィールド

注: Edition 2023 以降、string_view API が代わりに生成される場合があります。

これらのoneofフィールド定義のいずれかの場合

oneof example_name {
    string foo = 1;
    ...
}
oneof example_name {
    bytes foo = 1;
    ...
}

コンパイラは以下のアクセサメソッドを生成します

  • bool has_foo() const: oneof ケースが kFoo の場合に true を返します。
  • const string& foo() const: oneof ケースが kFoo の場合、フィールドの現在の値を返します。それ以外の場合、デフォルト値を返します。
  • void set_foo(::absl::string_view value):
    • 同じ oneof 内の他の oneof フィールドが設定されている場合、clear_example_name() を呼び出します。
    • このフィールドの値を設定し、oneof ケースを kFoo に設定します。
    • has_foo()true を返し、foo()value のコピーを返し、example_name_case()kFoo を返します。
  • void set_foo(const string& value): 最初の set_foo() と同じですが、const string 参照からコピーします。
  • void set_foo(string&& value): 最初の set_foo() と同じですが、渡された文字列からムーブします。
  • void set_foo(const char* value): 最初の set_foo() と同じですが、Cスタイルのヌル終端文字列からコピーします。
  • void set_foo(const char* value, int size): 最初の set_foo() と同じですが、ヌルターミネータバイトを探して決定するのではなく、明示的に指定されたサイズの文字列からコピーします。
  • string* mutable_foo():
    • 同じ oneof 内の他の oneof フィールドが設定されている場合、clear_example_name() を呼び出します。
    • oneof ケースを kFoo に設定し、フィールドの値を格納する変更可能な文字列オブジェクトへのポインタを返します。呼び出し前に oneof ケースが kFoo でなかった場合、返される文字列は空になります (デフォルト値ではありません)。
    • has_foo()true を返し、foo() は指定された文字列に書き込まれた任意の値を返し、example_name_case()kFoo を返します。
  • void clear_foo():
    • oneof ケースが kFoo でない場合、何も変更されません。
    • oneof ケースが kFoo の場合、フィールドを解放し、oneof ケースをクリアします。has_foo()false を返し、foo() はデフォルト値を返し、example_name_case()EXAMPLE_NAME_NOT_SET を返します。
  • void set_allocated_foo(string* value):
    • clear_example_name()を呼び出します。
    • 文字列ポインタが NULL でない場合: 文字列オブジェクトをフィールドに設定し、oneof ケースを kFoo に設定します。メッセージは割り当てられた文字列オブジェクトの所有権を取得し、has_foo()true を返し、example_name_case()kFoo を返します。
    • 文字列ポインタが NULL の場合、has_foo()false を返し、example_name_case()EXAMPLE_NAME_NOT_SET を返します。
  • string* release_foo():
    • oneof ケースが kFoo でない場合、NULL を返します。
    • oneof ケースをクリアし、フィールドの所有権を解放し、文字列オブジェクトのポインタを返します。これを呼び出した後、呼び出し元は割り当てられた文字列オブジェクトの所有権を取得し、has_foo() は false を返し、foo() はデフォルト値を返し、example_name_case()EXAMPLE_NAME_NOT_SET を返します。

Oneof Enumフィールド

enum型が与えられた場合

enum Bar {
  BAR_UNSPECIFIED = 0;
  BAR_VALUE = 1;
  BAR_OTHER_VALUE = 2;
}

oneof フィールド定義の場合

oneof example_name {
    Bar bar = 1;
    ...
}

コンパイラは以下のアクセサメソッドを生成します

  • bool has_bar() const: oneof ケースが kBar の場合に true を返します。
  • Bar bar() const: oneof ケースが kBar の場合、フィールドの現在の値を返します。それ以外の場合、デフォルト値を返します。
  • void set_bar(Bar value):
    • 同じ oneof 内の他の oneof フィールドが設定されている場合、clear_example_name() を呼び出します。
    • このフィールドの値を設定し、oneof ケースを kBar に設定します。
    • has_bar()true を返し、bar()value を返し、example_name_case()kBar を返します。
    • デバッグモード (すなわち、NDEBUG が定義されていない場合) では、valueBar に定義されている値のいずれにも一致せず、それがクローズドな列挙型である場合、このメソッドはプロセスをアボートします。
  • void clear_bar():
    • oneof ケースが kBar でない場合、何も変更されません。
    • oneof ケースが kBar の場合、フィールドの値と oneof ケースをクリアします。has_bar()false を返し、bar() はデフォルト値を返し、example_name_case()EXAMPLE_NAME_NOT_SET を返します。

Oneof 埋め込みメッセージフィールド

メッセージ型を考えると:

message Bar {}

oneof フィールド定義の場合

oneof example_name {
    Bar bar = 1;
    ...
}

コンパイラは以下のアクセサメソッドを生成します

  • bool has_bar() const: oneof ケースが kBar の場合に true を返します。
  • const Bar& bar() const: oneof ケースが kBar の場合、フィールドの現在の値を返します。それ以外の場合、フィールドが設定されていない Bar を返します (Bar::default_instance() の可能性があります)。
  • Bar* mutable_bar():
    • 同じ oneof 内の他の oneof フィールドが設定されている場合、clear_example_name() を呼び出します。
    • oneof ケースを kBar に設定し、フィールドの値を格納する変更可能な Bar オブジェクトへのポインタを返します。呼び出し前に oneof ケースが kBar でなかった場合、返される Bar はどのフィールドも設定されていません (つまり、新しく割り当てられた Bar と同一になります)。
    • これを呼び出した後、has_bar()true を返し、bar()Bar の同じインスタンスへの参照を返し、example_name_case()kBar を返します。
  • void clear_bar():
    • oneof ケースが kBar でない場合、何も変更されません。
    • oneof ケースが kBar に等しい場合、フィールドを解放し、oneof ケースをクリアします。has_bar()false を返し、bar() はデフォルト値を返し、example_name_case()EXAMPLE_NAME_NOT_SET を返します。
  • void set_allocated_bar(Bar* bar):
    • clear_example_name()を呼び出します。
    • Bar ポインタが NULL でない場合: Bar オブジェクトをフィールドに設定し、oneof ケースを kBar に設定します。メッセージは割り当てられた Bar オブジェクトの所有権を取得し、has_bar() は true を返し、example_name_case()kBar を返します。
    • ポインタが NULL の場合、has_bar()false を返し、example_name_case()EXAMPLE_NAME_NOT_SET を返します (動作は clear_example_name() を呼び出すのと同様です)。
  • Bar* release_bar():
    • oneof ケースが kBar でない場合、NULL を返します。
    • oneof ケースが kBar の場合、oneof ケースをクリアし、フィールドの所有権を解放し、Bar オブジェクトのポインタを返します。これを呼び出した後、呼び出し元は割り当てられた Bar オブジェクトの所有権を取得し、has_bar()false を返し、bar() はデフォルト値を返し、example_name_case()EXAMPLE_NAME_NOT_SET を返します。

マップフィールド

このmapフィールド定義の場合:

map<int32, int32> weight = 1;

コンパイラは以下のアクセサメソッドを生成します

  • const google::protobuf::Map<int32, int32>& weight();: 不変の Map を返します。
  • google::protobuf::Map<int32, int32>* mutable_weight();: 可変の Map を返します。

google::protobuf::Map は、プロトコルバッファでマップフィールドを格納するために使用される特別なコンテナ型です。以下のインターフェースからわかるように、std::mapstd::unordered_map メソッドのよく使われるサブセットを使用します。

template<typename Key, typename T> {
class Map {
  // Member types
  typedef Key key_type;
  typedef T mapped_type;
  typedef MapPair< Key, T > value_type;

  // Iterators
  iterator begin();
  const_iterator begin() const;
  const_iterator cbegin() const;
  iterator end();
  const_iterator end() const;
  const_iterator cend() const;
  // Capacity
  int size() const;
  bool empty() const;

  // Element access
  T& operator[](const Key& key);
  const T& at(const Key& key) const;
  T& at(const Key& key);

  // Lookup
  bool contains(const Key& key) const;
  int count(const Key& key) const;
  const_iterator find(const Key& key) const;
  iterator find(const Key& key);

  // Modifiers
  pair<iterator, bool> insert(const value_type& value);
  template<class InputIt>
  void insert(InputIt first, InputIt last);
  size_type erase(const Key& Key);
  iterator erase(const_iterator pos);
  iterator erase(const_iterator first, const_iterator last);
  void clear();

  // Copy
  Map(const Map& other);
  Map& operator=(const Map& other);
}

データを追加する最も簡単な方法は、通常のマップ構文を使用することです。たとえば、

std::unique_ptr<ProtoName> my_enclosing_proto(new ProtoName);
(*my_enclosing_proto->mutable_weight())[my_key] = my_value;

pair<iterator, bool> insert(const value_type& value) は、value_type インスタンスのディープコピーを暗黙的に引き起こします。新しい値を google::protobuf::Map に挿入する最も効率的な方法は次のとおりです。

T& operator[](const Key& key): map[new_key] = new_mapped;

標準マップでの google::protobuf::Map の使用

google::protobuf::Map は、std::mapstd::unordered_map と同じイテレータ API をサポートしています。google::protobuf::Map を直接使用したくない場合は、次のようにして google::protobuf::Map を標準マップに変換できます。

std::map<int32, int32> standard_map(message.weight().begin(),
                                    message.weight().end());

これはマップ全体のディープコピーを作成することに注意してください。

次のようにして、標準マップから google::protobuf::Map を構築することもできます。

google::protobuf::Map<int32, int32> weight(standard_map.begin(), standard_map.end());

不明な値の解析

ワイヤー上では、.proto マップは各キー/値ペアのマップエントリメッセージに相当し、マップ自体はマップエントリの繰り返しフィールドです。通常のメッセージ型と同様に、解析されたマップエントリメッセージに不明なフィールドが存在する可能性があります。たとえば、map<int32, string> として定義されたマップに int64 型のフィールドがある場合などです。

マップエントリメッセージのワイヤフォーマットに不明なフィールドがある場合、それらは破棄されます。

マップエントリメッセージのワイヤフォーマットに不明な enum 値がある場合、それは proto2、proto3、および editions で異なる方法で処理されます。proto2 では、マップエントリメッセージ全体が、包含するメッセージの不明なフィールドセットに入れられます。proto3 では、既知の enum 値であるかのようにマップフィールドに入れられます。editions の場合、デフォルトでは proto3 の動作を反映します。features.enum_typeCLOSED に設定されている場合、proto2 の動作を反映します。

Any

このようにAnyフィールドが与えられた場合

import "google/protobuf/any.proto";

message ErrorStatus {
  string message = 1;
  google.protobuf.Any details = 2;
}

生成されたコードでは、details フィールドのゲッターは google::protobuf::Any のインスタンスを返します。これにより、Any の値をパックおよびアンパックするための次の特殊なメソッドが提供されます。

class Any {
 public:
  // Packs the given message into this Any using the default type URL
  // prefix “type.googleapis.com”. Returns false if serializing the message failed.
  bool PackFrom(const google::protobuf::Message& message);

  // Packs the given message into this Any using the given type URL
  // prefix. Returns false if serializing the message failed.
  bool PackFrom(const google::protobuf::Message& message,
                ::absl::string_view type_url_prefix);

  // Unpacks this Any to a Message. Returns false if this Any
  // represents a different protobuf type or parsing fails.
  bool UnpackTo(google::protobuf::Message* message) const;

  // Returns true if this Any represents the given protobuf type.
  template<typename T> bool Is() const;
}

Oneof

このような oneof 定義が与えられた場合

oneof example_name {
    int32 foo_int = 4;
    string foo_string = 9;
    ...
}

コンパイラは、次の C++ enum 型を生成します

enum ExampleNameCase {
  kFooInt = 4,
  kFooString = 9,
  EXAMPLE_NAME_NOT_SET = 0
}

さらに、これらのメソッドも生成されます

  • ExampleNameCase example_name_case() const: どのフィールドが設定されているかを示す enum を返します。いずれも設定されていない場合は EXAMPLE_NAME_NOT_SET を返します。
  • void clear_example_name(): oneof フィールドセットがポインタ (Message または String) を使用している場合、オブジェクトを解放し、oneof ケースを EXAMPLE_NAME_NOT_SET に設定します。

列挙型

注: Edition 2024 以降、特定の機能設定で string_view API が生成される場合があります。このトピックの詳細については、列挙型名ヘルパーを参照してください。

以下のようなenum定義が与えられた場合

enum Foo {
  VALUE_A = 0;
  VALUE_B = 5;
  VALUE_C = 1234;
}

Protocol Buffer コンパイラは、同じ値のセットを持つ Foo という C++ enum 型を生成します。さらに、コンパイラは以下の関数を生成します。

  • const EnumDescriptor* Foo_descriptor(): この enum 型が定義する値に関する情報を含む、型の記述子を返します。
  • bool Foo_IsValid(int value): 指定された数値が Foo の定義値のいずれかに一致する場合に true を返します。上記の例では、入力が 0、5、または 1234 の場合に true を返します。
  • const string& Foo_Name(int value): 指定された数値の名前を返します。そのような値が存在しない場合は空の文字列を返します。複数の値がこの数を持つ場合、最初に定義されたものが返されます。上記の例では、Foo_Name(5)"VALUE_B" を返します。
  • bool Foo_Parse(::absl::string_view name, Foo* value): name がこの enum の有効な値名である場合、その値を value に代入して true を返します。それ以外の場合は false を返します。上記の例では、Foo_Parse("VALUE_C", &some_foo) は true を返し、some_foo を 1234 に設定します。
  • const Foo Foo_MIN: enum の最小有効値 (例では VALUE_A)。
  • const Foo Foo_MAX: enum の最大有効値 (例では VALUE_C)。
  • const int Foo_ARRAYSIZE: 常に Foo_MAX + 1 として定義されます。

整数を proto2 enum にキャストする際は注意してください。整数を proto2 enum 値にキャストする場合、その整数は enum の有効な値のいずれかでなければなりません。そうでなければ、結果は未定義になる可能性があります。疑問がある場合は、生成された Foo_IsValid() 関数を使用してキャストが有効かどうかをテストしてください。proto2 メッセージの enum 型フィールドを無効な値に設定すると、アサーション失敗を引き起こす可能性があります。proto2 メッセージを解析する際に無効な enum 値が読み取られた場合、それは不明なフィールドとして扱われます。これらのセマンティクスは proto3 で変更されています。int32 に収まる限り、任意の整数を proto3 enum 値にキャストしても安全です。無効な enum 値は、proto3 メッセージを解析する際にも保持され、enum フィールドアクセサによって返されます。

proto3 および editions enum を switch ステートメントで使用する際は注意してください。 Proto3 および editions enum は、指定されたシンボルの範囲外の値を持つ可能性のあるオープン enum 型です。(editions enum は、enum_type 機能を使用してクローズド enum に設定できます。) オープン enum 型の認識されない enum 値は、メッセージの解析時に保持され、enum フィールドアクセサによって返されます。デフォルトケースのないオープン enum の switch ステートメントは、すべての既知のフィールドがリストされていても、すべてのケースを捕捉できません。これにより、データ破損や実行時クラッシュなどの予期しない動作につながる可能性があります。常にデフォルトケースを追加するか、switch の外部で明示的に Foo_IsValid(int) を呼び出して、不明な enum 値を処理してください。

メッセージ型内に enum を定義できます。この場合、Protocol Buffer コンパイラは、enum 型自体がメッセージのクラス内にネストされて宣言されたかのように見えるコードを生成します。Foo_descriptor() および Foo_IsValid() 関数は静的メソッドとして宣言されます。実際には、enum 型自体とその値は、グローバルスコープでマングルされた名前で宣言され、typedef と一連の定数定義によってクラスのスコープにインポートされます。これは宣言順序の問題を回避するためにのみ行われます。マングルされたトップレベルの名前に依存しないでください。enum は本当にメッセージクラス内にネストされていると見なしてください。

拡張機能 (proto2 および edition のみ)

拡張範囲を持つメッセージが与えられた場合

message Foo {
  extensions 100 to 199;
}

プロトコルバッファコンパイラは、Foo に対して追加のメソッドを生成します: HasExtension()ExtensionSize()ClearExtension()GetExtension()SetExtension()MutableExtension()AddExtension()SetAllocatedExtension()、および ReleaseExtension()。これらの各メソッドは、最初のパラメータとして、拡張フィールドを識別する拡張識別子 (このセクションの後半で説明) を取ります。残りのパラメータと戻り値は、拡張識別子と同じ型の通常の (非拡張) フィールドに対して生成される対応するアクセサメソッドとまったく同じです。(GetExtension() は、特別なプレフィックスのないアクセサに対応します。)

エクステンション定義が与えられた場合:

extend Foo {
  optional int32 bar = 123;
  repeated int32 repeated_bar = 124;
  optional Bar message_bar = 125;
}

単一拡張フィールド bar の場合、プロトコルバッファコンパイラは bar という「拡張識別子」を生成します。これは、Foo の拡張アクセサで使用して、次のようにこの拡張にアクセスできます。

Foo foo;
assert(!foo.HasExtension(bar));
foo.SetExtension(bar, 1);
assert(foo.HasExtension(bar));
assert(foo.GetExtension(bar) == 1);
foo.ClearExtension(bar);
assert(!foo.HasExtension(bar));

メッセージ拡張フィールド message_bar の場合、フィールドが設定されていない場合、foo.GetExtension(message_bar) は、フィールドが設定されていない Bar (おそらく Bar::default_instance()) を返します。

同様に、繰り返し拡張フィールド repeated_bar の場合、コンパイラは repeated_bar という拡張識別子を生成します。これも Foo の拡張アクセサで使用できます。

Foo foo;
for (int i = 0; i < kSize; ++i) {
  foo.AddExtension(repeated_bar, i)
}
assert(foo.ExtensionSize(repeated_bar) == kSize)
for (int i = 0; i < kSize; ++i) {
  assert(foo.GetExtension(repeated_bar, i) == i)
}

(拡張識別子の正確な実装は複雑で、テンプレートの魔法のような使用を含みますが、拡張識別子がどのように機能するかを心配する必要はありません。)

エクステンションは、別の型の中にネストして宣言することができます。たとえば、一般的なパターンは次のようなものです。

message Baz {
  extend Foo {
    optional Baz foo_ext = 124;
  }
}

この場合、拡張識別子 foo_extBaz の内部にネストして宣言されます。次のように使用できます。

Foo foo;
Baz* baz = foo.MutableExtension(Baz::foo_ext);
FillInMyBaz(baz);

アリーナアロケーション

アリーナアロケーションは C++ 専用の機能で、Protocol Buffers を扱う際のメモリ使用量を最適化し、パフォーマンスを向上させるのに役立ちます。.proto でアリーナアロケーションを有効にすると、C++ 生成コードにアリーナを扱うための追加のコードが追加されます。アリーナアロケーション API の詳細については、アリーナアロケーションガイドを参照してください。

サービス

.proto ファイルに次の行が含まれている場合、

option cc_generic_services = true;

すると、Protocol Buffer コンパイラは、このセクションで説明されているように、ファイル内のサービス定義に基づいてコードを生成します。ただし、生成されたコードは特定の RPC システムに結びついていないため、特定のシステムに合わせたコードよりも間接的なレベルが多くなり、望ましくない場合があります。このコードを生成したくない場合は、ファイルに次の行を追加してください。

option cc_generic_services = false;

上記のいずれの行も指定されていない場合、オプションはデフォルトで false になります。これは、汎用サービスが非推奨であるためです。(2.4.0より前は、オプションのデフォルトは true であったことに注意してください)

.proto 言語サービス定義に基づく RPC システムは、システムに適したコードを生成するためのプラグインを提供する必要があります。これらのプラグインは、同じ名前の独自のクラスを生成できるように、抽象サービスが無効になっていることを要求する可能性が高いです。

このセクションの残りの部分では、抽象サービスが有効になっている場合に Protocol Buffer コンパイラが何を生成するかについて説明します。

インターフェース

サービス定義が与えられた場合

service Foo {
  rpc Bar(FooRequest) returns(FooResponse);
}

Protocol Buffer コンパイラは、このサービスを表す Foo クラスを生成します。Foo には、サービス定義で定義された各メソッドに対応する仮想メソッドがあります。この場合、メソッド Bar は次のように定義されます。

virtual void Bar(RpcController* controller, const FooRequest* request,
                 FooResponse* response, Closure* done);

パラメータは Service::CallMethod() のパラメータと同等ですが、method 引数は暗黙的であり、requestresponse はその正確な型を指定します。

これらの生成されたメソッドは仮想ですが、純粋仮想ではありません。デフォルトの実装は、メソッドが未実装であることを示すエラーメッセージとともに単に controller->SetFailed() を呼び出し、次に done コールバックを呼び出します。独自のサービスを実装する場合、この生成されたサービスをサブクラス化し、そのメソッドを適切に実装する必要があります。

FooServiceインターフェースをサブクラス化します。Protocol Bufferコンパイラは、Serviceのメソッドの実装を次のように自動的に生成します。

  • GetDescriptor: サービスのServiceDescriptorを返します。
  • CallMethod: 提供されたメソッド記述子に基づいて呼び出されるメソッドを決定し、それを直接呼び出し、リクエストとレスポンスのメッセージオブジェクトを正しい型にダウンキャストします。
  • GetRequestPrototype および GetResponsePrototype: 指定されたメソッドの正しい型のリクエストまたはレスポンスのデフォルトインスタンスを返します。

以下の静的メソッドも生成されます

  • static ServiceDescriptor descriptor(): 型の記述子を返します。これには、このサービスがどのようなメソッドを持ち、その入力型と出力型が何であるかに関する情報が含まれます。

スタブ

Protocol Buffer コンパイラは、サービスを実装するサーバーにリクエストを送信したいクライアントが使用する、すべてのサービスインターフェースの「スタブ」実装も生成します。Foo サービス (前述) の場合、スタブ実装 Foo_Stub が定義されます。ネストされたメッセージ型と同様に、typedef を使用して、Foo_StubFoo::Stub としても参照できるようにします。

Foo_StubFoo のサブクラスであり、以下のメソッドも実装しています

  • Foo_Stub(RpcChannel* channel): 指定されたチャネルでリクエストを送信する新しいスタブを構築します。
  • Foo_Stub(RpcChannel* channel, ChannelOwnership ownership): 指定されたチャネルでリクエストを送信し、そのチャネルを所有する可能性がある新しいスタブを構築します。ownershipService::STUB_OWNS_CHANNEL の場合、スタブオブジェクトが削除されると、チャネルも削除されます。
  • RpcChannel* channel(): このスタブのチャネルを返します (コンストラクタに渡されたもの)。

スタブは、チャネルのラッパーとしてサービスの各メソッドも実装します。メソッドのいずれかを呼び出すと、単に channel->CallMethod() が呼び出されます。

プロトコルバッファライブラリには RPC 実装は含まれていません。しかし、生成されたサービス クラスを任意の RPC 実装に接続するために必要なツールはすべて含まれています。必要なのは、RpcChannelRpcController の実装を提供するだけです。service.h のドキュメントで詳細を確認してください。

プラグイン挿入ポイント

C++ コードジェネレータの出力を拡張したいコードジェネレータプラグインは、指定された挿入ポイント名を使用して以下の種類のコードを挿入できます。各挿入ポイントは、特に明記されていない限り、.pb.cc ファイルと .pb.h ファイルの両方に表示されます。

  • includes: インクルードディレクティブ。
  • namespace_scope: ファイルのパッケージ/名前空間に属するが、特定のクラス内ではない宣言。他のすべての名前空間スコープコードの後に表示されます。
  • global_scope: ファイルの名前空間の外側のトップレベルに属する宣言。ファイルの最後に表示されます。
  • class_scope:TYPENAME: メッセージクラスに属するメンバ宣言。TYPENAME は、package.MessageType のような完全なプロト名です。クラス内の他のすべての公開宣言の後に表示されます。この挿入ポイントは .pb.h ファイルにのみ表示されます。

標準のコードジェネレータによって宣言されたプライベートクラスメンバーに依存するコードは生成しないでください。これらの実装詳細は、Protocol Buffers の将来のバージョンで変更される可能性があります。