C++ 生成コードガイド

プロトコルバッファコンパイラが、与えられたプロトコル定義に対して exactly どのような C++ コードを生成するかを説明します。

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

コンパイラの呼び出し

プロトコルバッファコンパイラは、--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.proto および src/bar/baz.proto を読み取り、4つの出力ファイル build/gen/foo.pb.hbuild/gen/foo.pb.ccbuild/gen/bar/baz.pb.hbuild/gen/bar/baz.pb.cc を生成します。コンパイラは必要に応じてディレクトリ build/gen/bar を自動的に作成しますが、build または build/gen は作成しません。これらはすでに存在している必要があります。

パッケージ

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

package foo.bar;

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

メッセージ

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

message Foo {}

プロトコルバッファコンパイラは、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 (libprotobuf-lite.lib) にリンクするだけで済みます。「ライト」ライブラリはフルライブラリよりもはるかに小さく、携帯電話などのリソースが制約されたシステムに適しています。

独自の 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* に変更されます。

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

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

  • static const Descriptor* descriptor(): 型のディスクリプタを返します。これには、その型に関する情報(どのようなフィールドがあるか、その型は何かなど)が含まれます。これは、プログラムからフィールドを検査するためにリフレクションとともに使用できます。
  • static const Foo& default_instance(): 新しく構築された Foo のインスタンスと同一の Foo の const シングルトンインスタンスを返します (したがって、すべての単一フィールドは設定されておらず、すべての繰り返しフィールドは空です)。メッセージのデフォルトインスタンスは、その 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(): フィールドの値を格納する mutable な 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 およびエディション) を返します。
  • 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 およびエディション) を返します。
  • bool has_foo(): フィールドが設定されている場合は true を返します。proto3 の optional フィールドおよびエディションの明示的な存在フィールドにのみ適用されます。

明示的な存在を持つ 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(): フィールドの値を格納する mutable な 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): 指定された 0 ベースのインデックスにある要素の値を、渡された文字列から移動して設定します。
  • void set_foo(int index, const char* value): C スタイルのヌル終端文字列を使用して、指定された 0 ベースのインデックスにある要素の値を設定します。
  • void set_foo(int index, const char* value, int size): 指定された 0 ベースのインデックスにある要素の値を、ヌル終端バイトを探すのではなく、明示的に指定されたサイズの 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 で定義されているいずれかの値と一致せず、それが閉じられた enum である場合、このメソッドはプロセスを中止します。
  • 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 ベースのインデックスにある要素を返します。このメソッドを [0, bar_size()) の範囲外のインデックスで呼び出すと、未定義の動作が発生します。
  • Bar* mutable_bar(int index): 指定された 0 ベースのインデックスにある要素の値を格納するミュータブルな Bar オブジェクトへのポインターを返します。このメソッドを [0, bar_size()) の範囲外のインデックスで呼び出すと、未定義の動作が発生します。
  • Bar* add_bar(): 新しい要素をフィールドの末尾に追加し、それへのポインターを返します。返される Bar は mutable であり、そのフィールドはいずれも設定されていません (つまり、新しく割り当てられた 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() を呼び出します。
    • string ポインタが NULL でない場合: string オブジェクトをフィールドに設定し、oneof ケースを kFoo に設定します。メッセージは割り当てられた string オブジェクトの所有権を取得し、has_foo()true を返し、example_name_case()kFoo を返します。
    • string ポインタが 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 で定義されているいずれかの値と一致せず、それが閉じられた enum である場合、このメソッドはプロセスを中止します。
  • 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::map および std::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::map および std::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、およびエディションでは異なる方法で処理されます。proto2 では、マップエントリメッセージ全体が、それを含むメッセージの不明なフィールドセットに格納されます。proto3 では、既知の enum 値であるかのようにマップフィールドに格納されます。エディションでは、デフォルトで 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;
}

プロトコルバッファコンパイラは、同じ値のセットを持つ 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 を定義できます。この場合、プロトコルバッファコンパイラは、enum 型自体がメッセージのクラスの中にネストして宣言されたかのように見えるコードを生成します。Foo_descriptor()Foo_IsValid() 関数は静的メソッドとして宣言されます。実際には、enum 型自体とその値は、マングリングされた名前でグローバルスコープに宣言され、typedef と一連の定数定義によってクラスのスコープにインポートされます。これは、宣言順序の問題を回避するためだけに行われます。マングリングされたトップレベル名に依存せず、enum が実際にメッセージクラスにネストされていると見なしてください。

拡張機能 (proto2 およびエディションのみ)

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

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

サービス

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

option cc_generic_services = true;

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

option cc_generic_services = false;

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

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

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

インターフェース

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

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

プロトコルバッファコンパイラは、このサービスを表す 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(): 型のディスクリプタを返します。これには、このサービスがどのようなメソッドを持ち、その入力および出力型が何であるかに関する情報が含まれます。

スタブ

プロトコルバッファコンパイラは、すべてのサービスインターフェースの「スタブ」実装も生成します。これは、サービスを実装するサーバーにリクエストを送信したいクライアントによって使用されます。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 の将来のバージョンで変更される可能性があります。