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.h、build/gen/foo.pb.cc、build/gen/bar/baz.pb.h、build/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つのクラス、Foo と Foo_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_type が VIEW に設定されている場合、代わりに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_viewAPI では削除されます。void clear_foo(): フィールドの値をクリアします。これを呼び出した後、has_foo()はfalseを返し、foo()はデフォルト値を返します。void set_allocated_foo(string* value):stringオブジェクトをフィールドに設定し、以前のフィールド値が存在する場合は解放します。stringポインタがNULLでない場合、メッセージは割り当てられたstringオブジェクトの所有権を取得し、has_foo()はtrueを返します。メッセージは割り当てられたstringオブジェクトをいつでも削除できるため、オブジェクトへの参照が無効になる可能性があります。それ以外の場合、valueがNULLの場合、動作はclear_foo()を呼び出すのと同じです。string* release_foo(): フィールドの所有権を解放し、stringオブジェクトのポインタを返します。これを呼び出した後、呼び出し元は割り当てられたstringオブジェクトの所有権を取得し、has_foo()はfalseを返し、foo()はデフォルト値を返します。
暗黙的な存在を持つ文字列/バイトフィールド
注: Edition 2023 以降、features.(pb.cpp).string_type が VIEW に設定されている場合、代わりに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オブジェクトをいつでも削除できるため、オブジェクトへの参照が無効になる可能性があります。それ以外の場合、valueがNULLの場合、動作はclear_foo()を呼び出すのと同じです。string* release_foo(): フィールドの所有権を解放し、stringオブジェクトのポインタを返します。これを呼び出した後、呼び出し元は割り当てられたstringオブジェクトの所有権を取得し、foo()は空の文字列/空のバイトを返します。
Cord サポート付きの単数バイトフィールド
v23.0 では、単一の bytes フィールド (oneof フィールドを含む) で absl::Cord のサポートが追加されました。単一の string、repeated 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()はvalueをabsl::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 が定義されていない場合) では、valueがBarで定義されているいずれかの値と一致しない場合、このメソッドはプロセスを中止します。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を返します。それ以外の場合、BarがNULLの場合、動作はclear_bar()を呼び出すのと同じです。Bar* release_bar(): フィールドの所有権を解放し、Barオブジェクトのポインタを返します。これを呼び出した後、呼び出し元は割り当てられたBarオブジェクトの所有権を取得し、has_bar()はfalseを返し、bar()はデフォルト値を返します。
繰り返し数値フィールド
このフィールド定義について:
repeated int32 foo = 1;
コンパイラは以下のアクセサメソッドを生成します
int foo_size() const: 現在フィールドに含まれる要素の数を返します。空のセットをチェックするには、このメソッドの代わりに、基盤となるRepeatedFieldのempty()メソッドの使用を検討してください。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_type が VIEW に設定されている場合、代わりにstring_view API が生成されます。
これらのいずれかのフィールド定義の場合
repeated string foo = 1;
repeated bytes foo = 1;
コンパイラは以下のアクセサメソッドを生成します
int foo_size() const: 現在フィールドに含まれる要素の数を返します。空のセットをチェックするには、このメソッドの代わりに、基盤となるRepeatedFieldのempty()メソッドの使用を検討してください。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: 現在フィールドに含まれる要素の数を返します。空のセットをチェックするには、このメソッドの代わりに、基盤となるRepeatedFieldのempty()メソッドの使用を検討してください。Bar bar(int index) const: 指定された 0 ベースのインデックスにある要素を返します。このメソッドを [0, bar_size()) の範囲外のインデックスで呼び出すと、未定義の動作が発生します。void set_bar(int index, Bar value): 指定された 0 ベースのインデックスにある要素の値を設定します。デバッグモード (つまり NDEBUG が定義されていない場合) では、valueがBarで定義されているいずれかの値と一致せず、それが閉じられた enum である場合、このメソッドはプロセスを中止します。void add_bar(Bar value): 指定された値で新しい要素をフィールドの末尾に追加します。デバッグモード (つまり NDEBUG が定義されていない場合) では、valueがBarで定義されているいずれかの値と一致しない場合、このメソッドはプロセスを中止します。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: 現在フィールドに含まれる要素の数を返します。空のセットをチェックするには、このメソッドの代わりに、基盤となるRepeatedFieldのempty()メソッドの使用を検討してください。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を返します。
- 同じ oneof 内の他の oneof フィールドが設定されている場合、
void clear_foo():- oneof ケースが
kFooでない場合、何も変更されません。 - oneof ケースが
kFooの場合、フィールドの値と oneof ケースをクリアします。has_foo()はfalseを返し、foo()はデフォルト値を返し、example_name_case()はEXAMPLE_NAME_NOT_SETを返します。
- oneof ケースが
他の数値フィールド型 (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を返します。
- 同じ oneof 内の他の oneof フィールドが設定されている場合、
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を返します。
- 同じ oneof 内の他の oneof フィールドが設定されている場合、
void clear_foo():- oneof ケースが
kFooでない場合、何も変更されません。 - oneof ケースが
kFooの場合、フィールドを解放し、oneof ケースをクリアします。has_foo()はfalseを返し、foo()はデフォルト値を返し、example_name_case()はEXAMPLE_NAME_NOT_SETを返します。
- oneof ケースが
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 ケースが
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 が定義されていない場合) では、
valueがBarで定義されているいずれかの値と一致せず、それが閉じられた enum である場合、このメソッドはプロセスを中止します。
- 同じ oneof 内の他の oneof フィールドが設定されている場合、
void clear_bar():- oneof ケースが
kBarでない場合、何も変更されません。 - oneof ケースが
kBarの場合、フィールドの値と oneof ケースをクリアします。has_bar()はfalseを返し、bar()はデフォルト値を返し、example_name_case()はEXAMPLE_NAME_NOT_SETを返します。
- oneof ケースが
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を返します。
- 同じ oneof 内の他の oneof フィールドが設定されている場合、
void clear_bar():- oneof ケースが
kBarでない場合、何も変更されません。 - oneof ケースが
kBarと等しい場合、フィールドを解放し、oneof ケースをクリアします。has_bar()はfalseを返し、bar()はデフォルト値を返し、example_name_case()はEXAMPLE_NAME_NOT_SETを返します。
- oneof ケースが
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を返します。
- oneof ケースが
マップフィールド
この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_type が CLOSED に設定されている場合、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_ext は Baz の内部にネストして宣言されます。次のように使用できます。
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 引数が暗黙的であり、request と response がその正確な型を指定している点が異なります。
これらの生成されたメソッドは仮想ですが、純粋仮想ではありません。デフォルトの実装は、メソッドが未実装であることを示すエラーメッセージとともに単に controller->SetFailed() を呼び出し、その後 done コールバックを呼び出します。独自のサービスを実装する場合、この生成されたサービスをサブクラス化し、そのメソッドを適切に実装する必要があります。
FooはServiceインターフェースをサブクラス化します。Protocol Bufferコンパイラは、Serviceのメソッドの実装を次のように自動的に生成します。
GetDescriptor: サービスのServiceDescriptorを返します。CallMethod: 提供されたメソッドディスクリプタに基づいて呼び出されるメソッドを決定し、リクエストとレスポンスメッセージオブジェクトを正しい型にダウンキャストして直接呼び出します。GetRequestPrototypeおよびGetResponsePrototype: 指定されたメソッドの正しい型のリクエストまたはレスポンスのデフォルトインスタンスを返します。
以下の静的メソッドも生成されます。
static ServiceDescriptor descriptor(): 型のディスクリプタを返します。これには、このサービスがどのようなメソッドを持ち、その入力および出力型が何であるかに関する情報が含まれます。
スタブ
プロトコルバッファコンパイラは、すべてのサービスインターフェースの「スタブ」実装も生成します。これは、サービスを実装するサーバーにリクエストを送信したいクライアントによって使用されます。Foo サービス (前述) の場合、スタブ実装 Foo_Stub が定義されます。ネストされたメッセージ型と同様に、typedef を使用して、Foo_Stub を Foo::Stub としても参照できるようにします。
Foo_Stub は Foo のサブクラスであり、以下のメソッドも実装しています。
Foo_Stub(RpcChannel* channel): 指定されたチャネルで要求を送信する新しいスタブを構築します。Foo_Stub(RpcChannel* channel, ChannelOwnership ownership): 指定されたチャネルで要求を送信し、そのチャネルを所有する可能性のある新しいスタブを構築します。ownershipがService::STUB_OWNS_CHANNELの場合、スタブオブジェクトが削除されるときにチャネルも削除されます。RpcChannel* channel(): このスタブのチャネルを返します (コンストラクタに渡されたもの)。
スタブはさらに、サービスの各メソッドをチャネルのラッパーとして実装します。いずれかのメソッドを呼び出すと、単に channel->CallMethod() が呼び出されます。
プロトコルバッファライブラリには RPC 実装は含まれていません。しかし、生成されたサービス クラスを任意の RPC 実装に接続するために必要なすべてのツールが含まれています。必要なのは、RpcChannel と RpcController の実装を提供するだけです。service.h のドキュメントで詳細を確認してください。
プラグイン挿入ポイント
C++ コードジェネレータの出力を拡張したいコードジェネレータプラグインは、指定された挿入ポイント名を使用して以下のタイプのコードを挿入できます。各挿入ポイントは、特に明記されていない限り、.pb.cc ファイルと .pb.h ファイルの両方に表示されます。
includes: インクルードディレクティブ。namespace_scope: ファイルのパッケージ/名前空間に属するが、特定のクラス内には属さない宣言。他のすべての名前空間スコープコードの後に表示されます。global_scope: ファイルの名前空間の外のトップレベルに属する宣言。ファイルの最後に表示されます。class_scope:TYPENAME: メッセージクラスに属するメンバー宣言。TYPENAMEは、package.MessageTypeのような完全なプロト名です。クラス内の他のすべての公開宣言の後に表示されます。この挿入ポイントは.pb.hファイルにのみ表示されます。
標準のコードジェネレータによって宣言されたプライベートクラスメンバーに依存するコードは生成しないでください。これらの実装詳細は、Protocol Buffers の将来のバージョンで変更される可能性があります。