google C++スタイルガイド( https://google.github.io/styleguide/cppguide.html )の要約メモ。
C++バージョン
- C++17を使え。非標準の拡張は使うな。
ヘッダファイル
ヘッダはself-containedに
- .ccファイルには.hファイルを対応させろ。例外: unit testやmain()だけを含む小さい.ccファイル。
- .hファイルはself-containedにし、好きな場所からincludeできるようにしろ。
- 関数テンプレートやinline関数の定義はなるべく宣言と同じファイルに書け。例外: 単独.ccファイルでだけ使うテンプレートは.ccファイルに置いていい。
- includeの場所が限られるようなファイルは.incとせよ
#defineガード
- .hは必ず#defineガードをつけろ。シンボルはソースツリー中のファイルのフルパス、たとえば/foo/bar/baz.hならFOO_BAR_BAZ_H_
forward declaration(前方宣言)
- forward declaration(定義のないクラス/関数/テンプレートの宣言)は避け、必要なヘッダをincludeせよ。
インライン関数
- インライン化するのは10行以下くらいの小さい関数。デストラクタやループ/switchを含む関数は通常インライン化はやめておけ。
includeの順序
- related header(foo.ccに対するfoo.h)->Cシステムヘッダ->C++標準ライブラリヘッダ->他のライブラリヘッダ->自分のプロジェクトのヘッダ。グループ間には空行を入れ、グループ内ではalphabetical order。
- 依存しているシンボルを含むヘッダは全てincludeせよ。foo.hが(現在のところ)bar.hをincludeしていることに依存するな。
- includeのパスはプロジェクト内のソースツリーからのフルパスで。.や..を使うな。
スコーピング
namespace
- コードをnamespaceに入れろ、usingディレクティブを使うな
- namespaceの閉じ括弧の後には次のようなコメントを入れろ: // namespace mynamespace
- namespaceはinclude以外の全てを囲む。インデントなし。
- namespace alias (like namespace baz = ::foo::bar::baz;)は.h内で定義するな。例外: APIの一部でないinternal onlyなnamespace。
- .ccファイル中の定義がファイル外で不要なら無名のnamespaceで囲うかstatic宣言しろ。
メンバ関数でないstatic変数、グローバル関数
- メンバ関数でない関数はnamespace内に置け。単に関数をグルーピングするためにクラスを使うな。クラスのstatic関数はクラスのインスタンスかstaticデータに深く関わるものであるべき。
ローカル変数
- ローカル変数は最小スコープで、宣言時に初期化。
staticおよびグローバル変数
- static storage durationはデストラクタが実質何もしない場合以外禁止。関数スコープのstatic変数の動的初期化はOK、staticクラスメンバやnamespaceスコープ変数の動的初期化は非推奨。
コンストラクタ・デストラクタの呼び出し順序が制御できないので初期化前や破棄後のオブジェクトにアクセスしてしまう危険がある。joinされてないスレッドが走り続けてる場合も破棄後のオブジェクトにアクセスする危険あり。 - 基本型やconstexprはstatic strage duration可。
- コンストラクタは複雑。コンストラクタの中で使うクラス等のコンストラクタはconstexpr修飾すべし(C++標準でいうconstant initialization)。
- ローカルでない変数の動的初期化は不可。例外: 他の初期化との依存関係がない場合。
- 具体的には、stringの代わりにstringリテラルを指すcharポインタ、map/setの代わりにint arrayのarray(など)
- 自作オブジェクトをstatic storage durationにするときはconstexprコンストラクタとtrivialな(実質何もしない)デストラクタを持たせろ。
- どうしても他に方法がなければ関数ローカルなstaticなポインタもしくは参照として動的にオブジェクトを作り、破棄はしないようにしろ。
thread_local変数
- 関数ローカルでないthread_local変数はコンパイル時定数で初期化しろ。thread_local変数はスレッド作成時に初期化されるがグローバル変数に性質が近い。
- 参考: ABSL_CONST_INIT https://github.com/abseil/abseil-cpp/blob/master/absl/base/attributes.h#L595
クラス
コンストラクタ内の作業
- コンストラクタ中では仮想メソッド呼び出しや失敗する可能性のある初期化を避けろ。factory methodやInit()メソッドを使え。 (see https://abseil.io/tips/42)
暗黙の型変換
- 暗黙の型変換を自分で定義するな。型変換演算子や1つの引数で呼ぶことができるコンストラクタにはexplicit(C++11以降)をつけろ。
- ただし複数の引数をとるコンストラクタやstd::initializer_listを引数にとるコンストラクタはexplicitなし。(MyType m = {1,2,3};はアリにしたい)
コピー可・ムーブ可な型
- クラスのpublic APIでクラスがコピー可、ムーブのみ、コピーもムーブも不可のいずれかをはっきりさせろ。
つまり、明示的にコピー(ムーブ)コンストラクタ/コピー(ムーブ)代入演算子をpublic定義するか、ムーブオンリーならムーブ操作を定義してコピー操作をdelete、
コピーもムーブも不可ならpublicセクションでコピー操作をdeleteしろ(ムーブ操作は勝手にdeleteされるが明示的に書いてもいい)。
ムーブ可とは一時変数からの初期化や代入ができること。さらに、コピー可とはもとのオブジェクトを壊さずに同型のオブジェクトから初期化や代入ができること。つまりコピー可なか必ずムーブ可。
ユーザ定義型について、コピー挙動はコピーコンストラクタとコピー代入演算子によって、
ムーブ挙動は、もし定義されていればムーブコンストラクタとムーブ代入演算子によって、なければコピーコンストラクタとコピー代入演算子によって定義される。 - パブリックメンバしかないstruct、規定型がコピー・ムーブ不可の場合は自明なので省略していい。
- コピー/ムーブ挙動の意味がカジュアルユーザにとって不明確ならコピー可・ムーブ可にするな。コピー可な型のムーブ操作はパフォーマンス最適化にのみ貢献し、実装を複雑にするので効率向上が有意な場合以外は避けろ。
- スライシングのリスクを避けるために、継承される可能性のある型にpublic代入演算子やコピー/ムーブコンストラクタを定義するのはなるべく避けろ。
基底クラスをコピー可にしたければpublicなClone()メソッドとprotectedなコピーコンストラクタを用意しろ。
struct vs class
- structはアクセサ以外の機能を持たないpassiveなオブジェクトにだけ使え。言語仕様上はstructとclassにほとんど差はないが、そういう規約とする。
struct vs pairs/tuples
- 要素に意味のある名前をつけられるときはpairやtupleよりstructがよい。firstとかsecondとかより意味がわかりやすいから。
継承
- 継承よりcompositeを好め。継承はpublicにしろ。多重継承は許すが実装の多重継承は強く非推奨。継承はis-a関係のときに限れ。オーバライドする関数にはoverride/finalをつけろ。
演算子オーバーロード
- 演算子オーバーロードは慎重に、自然で一貫した挙動が定義できるときだけにしろ。ユーザ定義のリテラルは使うな。
- 演算子定義は自分の作った型に対してのみにし、同じ.h,.ccファイル、namespaceに置け。(多重定義による衝突のとき動作が不定になるので、そのリスクを避ける)
- オブジェクトに変更を加えないバイナリオペレータは非メンバ関数として実装すべし。(メンバ関数にすると暗黙の型変換が右辺にだけかかるので非対称な動作になる)
- &&、||、,(コンマ)、単項&はオーバーロードするな。
変数のアクセスコントロール
- 定数以外のデータメンバはprivateにしろ。不変式の保証がわかりやすくなる。
宣言順序
- クラス定義はpublic:、protected:、private:の順とし、似た宣言は近くにまとめろ。セクション内では型->定数->ファクトリ関数->コンストラクタ->代入演算子->デストラクタ->その他メソッド->データメンバの順で。
- クラス定義内に大きいメソッドの定義を入れるな。
関数
出力引数
- 出力はできたら戻り値で。入力引数にはconstをつけろ。output引数はinput引数の後ろに。
関数は短く
- 関数は短く。40行までが目安。あとで修正するときにわかりやすくなる。
参照型の引数
- lvalue参照渡しの引数にはconstをつけろ。(e.g., void Foo(const std::string &in, std::string *out);)
- googleでの強い規約: 入力引数は値渡しかconst参照渡し、出力引数はポインタ。入力引数をconstポインタにするのは可だがconstでない参照パラメータは絶対に許さない。
- const T&の代わりにconst T*は許すけど、nullポインタを渡す可能性があるとか、関数の中でポインタを保存するとか、ちゃんと理由がある時だけ。
関数オーバーロード
- 関数オーバーロードは、読み手が関数を呼ぶ側のコードを読んだときにどのオーバロードが呼び出されているか考えずに動作が理解できるときだけ使え。意味論的にぜんぶ同じで、動作を説明したコメントが共通で済む感じ。
デフォルト引数
- デフォルト引数は、非仮想関数で、デフォルトが常に同じ値だと保証できるときだけOK。迷ったらオーバロードにしておけ。
デフォルト引数では関数ポインタのシグネチャが呼び出し型とずれたりして混乱するが、オーバロードではこの問題は防げる。
戻り値型の後置文法
- 戻り値型の後置文法(auto foo(int x) -> int;)は、通常の文法が実用的でないかとても読みづらい時だけ使え。
- ラムダ式の戻り値型を指定するには後置文法しかないので、これはアリ。
- 戻り値型がテンプレートパラメータに依存するとき、つまりtemplate auto add(T t, U u) -> decltype(t + u); みたいなケースでは読みやすくなるのでアリ。
google独自のテクニック
所有権とスマートポインタ
- 動的に割り当てたオブジェクトはなるべく単一の、固定の所有者に持たせるようにしろ。所有権の受け渡しにはなるべくスマートポインタを使え。
- 他のコードがオブジェクトにアクセスしないといけないときはコピーを渡すか所有権を渡さずにポインタや参照を渡すとよい。
- 共有所有権はちゃんとした理由があるときだけ使い、なるべくstd::shared_ptrを使え。
cpplint
- cpplint.pyをスタイルチェックに使え。https://raw.githubusercontent.com/google/styleguide/gh-pages/cpplint/cpplint.py
その他のC++の機能
右辺値参照(rvalue reference)
- 右辺値参照はムーブコンストラクタとムーブ代入演算子を定義するときに使ってよい。パフォーマンスに十分貢献するときは片方はconst Foo&をとり他方はFoo&&をとるようなオーバロードの対を書いてよい。
- perfect forwardingをサポートするためにforwarding referenceをstd::forwardと対応させて使ってよい。
friend
- friendクラスはビルダークラスなどちゃんと理由があれば使って良い。
例外
- C++の例外は使うな。
noexcept
- パフォーマンス上意味があって意味論的に正しい場合はnoexceptをつけてよい。例外が完全に禁止されているような環境では一貫してnoexceptを推奨する。
RTTI (Run Time Type Information)
- RTTIの使用はユニットテストではOK、それ以外では避けろ。実行時にRTTIで型を調べないといけないならクラス階層設計が間違っていることが多い。
- RTTIがやりたくなったら仮想関数かvisitorパターンのようなdouble-dispatchソリューションを検討しろ。
キャスト
- C++スタイルキャストか、{}初期化(e.g., int64 y = int64{1} << 42;)を使い、Cスタイルキャストは避けろ。
- 数値型のアップキャストには{}を使え。情報が失われるときはコンパイルエラーになる。
- 値の変換が起こる場合、ポインタを親クラスの型にアップキャストする場合、親クラスから子クラスへのポインタの強制キャストをする場合はstatic_castを使え。
- constを取り除くときはconst_castを使え。
- 意図的に安全でない型変換をするときはreinterpret_castを使え。absl::bit_castも選択肢として検討せよ。
- ビット列を他の型として解釈しなおすときはabsl::bit_castを使え。
ストリーム
- デバッグログやテスト用を中心に、単純に使える時はストリームを使え。
前置インクリメント/デクリメント演算子
- イテレータや他のテンプレートオブジェクトには前置++/--演算子を使え。スカラー(オブジェクトでない)値についてはどっちでもいい。
const
- constは意味のある時はいつでもつけろ。
- 引数のconst T&やconst T*はつけるべき。値渡しの引数のconstは呼び出し側にとっては意味がないので関数の宣言につけるのは非推奨。
- オブジェクトを書き換えないメソッドはconstを付けろ。
- あるクラスのconst操作はすべて並行に実行しても安全であるべき。それが現実的でなければスレッドアンセーフだとドキュメントしろ。
- const int* fooのほうがint const *fooより推奨。
constexpr
- constexprは真の定数とそれらの定義をサポートする関数につけろ。
整数型
- ループカウンタなどオーバフローの心配がないとわかっている整数にはintをよく使う。それ以外はint16_tなどを使え。size_tやptrdiff_tも適切に使ってよい。
- uint32_tなどのunsigned型はビットパターンを示す時など以外に使うな。ある値が決して負にならないことを示すためにunsignedを使うな、代わりにassertionを使え。
- STLではコンテナのサイズにunsigned整数を使っているが負の値が整数の最大値にwrap aroundしてしまうのでよくない、だがいまさら直せない。
- signedとunsignedを混ぜるな、unsignedはできるだけ使うな、ポインタやサイズの代わりにイテレータとコンテナをなるべく使え。
64bitポータビリティ
- コードは32/64bit対応でないといけない。print、比較、構造体のアライメントに注意。
- printf()は32/64bit対応において問題があるので極力避けろ。代わりにabsl::StrCat()やatsl::Substitute()やostreamを使え。
- sizeof(void *) != sizeof(int)であることに注意。ポインタと同じサイズの整数が必要ならintptr_tを使え。
- 特にディスクに格納する時構造体のアライメントに気を付けろ。64bit整数のメンバを持つ構造体は64bitシステムでは8バイトアラインされる。
- 64bit定数の初期化にはint64_t foo{0x123456789};またはuint64_t bar{3ULL << 43};のような{}記法を使え。
プリプロセッサマクロ
- 特にヘッダにおいてマクロ定義を避け、極力インライン関数、enum、const変数を使え。C++のAPIを定義するのにマクロを使うな。
- 低レベルコードでは仕方がないこともあるが、他の方法がないかよく考えろ。
- 仕方なくマクロを使う時は: .hに書くな、使う直前にdefineして直後でundefしろ、既存のマクロをundefして置き換えたりするな、##で名前を合成するのは極力避けろ
0とnullptr/NULL
- ポインタにはnullptrを、charにはリテラル0でなく'\0'を使え。C++03では0よりはNULLを使え。
sizeof
- なるべくsizeof(type)よりsizeof(varname)を使え(あとでのコード書き換えに強い)。
型推論
- 型推論はコードが分かりやすくなるか安全になるときに使え。単に明示的に型を書く面倒さを避けるために使うな。コードベースを知らない他所のチームの人が読んで型が不明確でないようにしろ。
- 関数のテンプレート引数の推論はほぼいつもOK。
- ローカル変数は明らかに冗長な宣言をきれいにできるときはOK。
- 戻り値の型推論はreturn文の数が少数で他のコードが少ないとき、かつ戻り値が使われるスコープが狭いときだけ。ヘッダで定義するパブリック関数では基本推論はやめておけ。
- ラムダ式のパラメータをautoにするのはスコープが狭いか呼ばれる引数が明白な時(sortとか)だけ。
- structured bindings: pairやtupleの要素に名前を与えられるのはよいことだがそもそもpairやtupleをなるべく使うな。構造体に使うときはコメントでどの要素がどの変数にバインディングされているか明記しろ。
クラステンプレート引数推論
- クラステンプレート引数推論 (e.g., std::array a = {1, 2, 3};)はC++17以前に書かれたコードでは意図通り動かないことがあるので基本使うな。
lambda式
- 適切な時はlambda式を使え。lambdaが現在のスコープの外に渡されるときは明示的なキャプチャを使え(解放されたポインタへの参照が起こる可能性があるため)
- 参照によるデフォルトキャプチャ([&])はlambdaの寿命がキャプチャされるいずれの変数より短い場合だけ使え。
- 値によるデフォルトキャプチャ([=])はキャプチャされた変数が一眼で明らかな、単純で短いlambdaにだけ使え。
- []内でのややこしい初期化は(できるけど)やめ、外側のスコープからの単純なキャプチャだけしろ。
テンプレートメタプロラミング
- 複雑なテンプレートメタプログラミングは極力避けろ。デバッグやメンテナンスが大変。どうしても必要なら可能な限り複雑さを避け、ユーザから隠蔽するようにしろ。
- ユーザが誤用した時のエラーメッセージが極力わかりやすくなるよう注意を払え。
Boost
- boostの利用は決められたサブセットのみ(テンプレートの利用法や関数型ぽいコーディングスタイルが合わないから)。
- ホワイトリスト: https://google.github.io/styleguide/cppguide.html#Boost
std::hash
- std::hashはすでにサポートされている型について使ってもいいが新しい型についての定義を追加するな。
その他のC++の機能
- テンプレートが複雑になるのでコンパイル時有理数()は使うな
- コンパイラのサポート状況が悪いので / は使うな
- サポート状況とセキュリティ脆弱性から、ヘッダも。
非標準のC++拡張
- GCCの__attribute__、elvis operator(a?:b)など、非標準の拡張は基本使うな。
別名
- publicな別名(alias)はAPIの利用者のために役立つものだけにし、はっきりドキュメントしろ。実装のためなら.ccファイルに書け。
命名
一般的な命名ルール
- 可読性を重視しアクロニムや略は最小限に。単語の中の文字を省いて短くするな。wikipediaにあるレベルの略なら許す。
ファイル名
- ファイル名は小文字で、-や_を使ってよい。デフォルトは_。
型名
- 全ての型(class, struct, enum, type alias, type template parameter)について、いわゆるPascal caseで(e.g., MyExcitingClass, MyExcitingEnum)。
変数名
- 変数名やデータメンバは小文字で_区切り。class(but not struct)のデータメンバは最後に をつける(e.g., a_local_variable, a_data_member, a_struct_member)。
定数名
- const/constexpr定数はkから初めてMixed case(e.g., const int kDaysInAWeek = 7; const int kAndroid8_0_0 = 24;)
関数名
- 普通の関数はmixed case、アクセサ・ミューテータは変数名と同じように名付けてもよい(e.g., set_count(int count);)が強制ではない。
namespace
- namespace名は小文字で。トップレベルでは衝突に注意。
enum
- enumの名前はmixed case(e.g., MyEnum)、中の定数名は定数のように(e.g., kFooBar)、またはマクロのように(e.g., FOO_BAR)。
マクロ
- そもそもマクロはやめておけ、しかし使うならFOO_BARスタイルで。
命名規則の例外
- C/C++の既存のなにかに似たものを作る時はもとの名前に寄せてもいい。(e.g, LONGLONG_MAX after INT_MAX)
コメント
コメントスタイル
- /* */と//のどっちでもいいが//がずっと一般的。一貫してどちらかを使え。
ファイル先頭のコメント
- 1つしかエンティティがなくてその頭にコメントがついている場合以外は必須。
- ライセンス記述は全てのファイルに書け。
- 人のコードに大幅に手を加えるならauthorラインを消すのもよい。新しいファイルにはコピーライト表記やauthorラインは通常書くな。
- .hファイルの先頭には1-2文の概要説明を。
- .hと.ccに重複コメントを書くな(一方を変え忘れる)
クラスコメント
- 見て明らかな時以外、全てのクラスには
- いつどのようにクラスを使うか、また同期やマルチスレッドアクセスに関する前提を書く。
- 使い方の単純なコード例があるとよい。
- 使い方に関するコメントは.hに、内部動作に関するコメントは.ccに。
関数宣言へのコメント
- 見て明らかな時以外、全ての関数にはそれが何なのか、どう使われるかのコメントをつけろ。
- 命令形ではなく三人称の動詞から始めろ (e.g., Opens a file)
- 使い方を書き内部動作を書くな
- デストラクタに"destroys this object"とコメントつけるみたいな分かり切ったことは書くな。そういうときは何も書かなくていい。
関数定義へのコメント
- 実装についてトリッキーなことがあれば書く。
- 宣言のコメントのコピーはするな。
変数へのコメント
- 基本的には名前に語らせろ。時にはコメントが必要。
- -1が無効値を示すなどは書け。
- 全てのグローバル変数には、それが何で何のために使われてなぜグローバルでないといけないか書け。
実装に関するコメント
- ややこしいブロックの手前か行の後ろに書け。
関数の引数へのコメント
- 引数がリテラル定数で、複数の呼び出しで同一の定数が与えられることが暗黙の前提なときは、名前のついた定数を使ってそれを明示しろ。
- 関数signatureをboolからenumに変えると意味をコード中で伝えられる。
- 複数の設定項目はひとつのoption構造体/クラスに入れろ。名前がついて意味がわかりやすくなる、引数の数が減って呼び出しがわかりやすくなる、引数を追加した時に呼び出しコードを変更する必要がなくなる。
- 関数呼び出しでの複雑にネストされた式は名前をつけた変数にしろ。
- コメントをつけるのは最後の手段としろ。
分かりきったことは書くな
- C++をよく理解した人にも分かりにくいのでなければ動作をそのまま書くな、"why"を書け。
句読点、スペリング、文法
- 読みやすくなるようちゃんと書いてね。
TODOコメント
- all capital (TODO)、一時的、短期的ソリューションをマークするのに使う。責任者を書け (e.g., TODO(kl@gmail.com): Use a "*" here for concatenation operator.)
フォーマッティング
行の長さ
- 最大80文字
- 例外: 切ると読みにくくなるコメント、長いstringリテラル、include、ヘッダガード、using宣言
非ASCII文字
- 基本書くな。
- ユーザに見せる文字はたとえ英語でもソースコードに書くな。
- テストコードとかデリミタとか、ありな場合もある。
- 書くならUTF-8で。読みやすくなるならhex encodingもよい。\uXXXXエスケープが入ったリテラルはu8 prefixをつけてUTF-8であることを保証せよ。
- C++11の char16_tとchar32_tは使うな。同様にwchar_tも。ただし、wchar_tを使うwindows APIとのやりとりに必要な場合を除く。
スペースvsタブ
- スペース2字下げに統一。tabは使うな(エディタを設定しろ)
関数の宣言と定義
- 戻り値型は関数名と同じ行に、引数もおさまれば同じ行に(いずれもおさまらなければ改行)。
- 開き括弧は必ず関数名と同じ行に
- 関数名と(の間、(と引数の間にはスペースなし
- {の前では改行しない
- }は最後に独立とした行として、または{と同じ行に
- パラメータはなるべく揃えて
- デフォルトのインデントはスペース2つ、改行して書いた引数の前はスペース4つ
- アトリビュートやアトリビュートに展開されるマクロは関数の定義・宣言の一番最初、戻り値型の前に(e.g., ABSL_MUST_USE_RESULT bool IsOk();)
lambda式
- 引数列と本体({}区間)はふつうの関数のように、キャプチャリストはふつうのコンマ区切り列のように。
- 参照によるキャプチャのときは&と変数名の間にスペースを入れるな(e.g., auto x_plus_n = [&x](int n) -> int { return x + n; })
- 短いlambdaは関数の引数のとこにインラインで入れてもいいよ
浮動小数点リテラル
- exponential表記でも必ず小数点をつけ両側に数字を書く(bad: 1.fとか.1L)。
- 浮動小数点型の変数を整数で初期化しても良い(e.g., float f2 = 1;)が、exponential表記(e.g., 1248.0e6)は決して整数リテラルにならないことに注意せよ。
関数呼び出し
- 全て1行にするか、(の後で改行して引数を次の行以降に書くか。他に制約がなければ。行数を減らすように。複数引数を1行に書くのもあり。
- 引数について、(の後と)の前にスペースを入れるな。
{}初期化リスト
- 関数呼び出しと同じように。
条件式
- ()の内側にはスペースなし(ただし一貫して、コードの他の場所に合わせろ)
- ifとelseは別の行に
- ifと(の間、)と{の間には必ずスペースを入れる
- 短い条件文は1行にしていい(e.g., if (x == kFoo) return new Foo();)ただしelseがつくときは不許可
- 中身が1行だけならifの{}は省略していいがifとelseで一貫させろ。
ループとswitch文
- switch文ではcaseやdefault全体を含むブロックを囲むのに{}を使ってよい。
- caseの後のブロックは{}で囲んでも囲わなくてもよい。
- defaultは必ず書け。絶対にdefaultにならないはずならエラーにしろ。
- fall-through(ひとつのcaseから次のcaseにbreakせずに処理が写る)はABSL_FALLTHROUGH_INTENDEDでアノテートしろ。複数行空のcaseを並べるときは例外。
- 1文だけのループでの{}は任意。
- 空ループは{}とだけするか改行やコメントを入れる。;は置かない。 (ok: while (condition) continue; or while (condition) {}; bad: while (condition);)
ポインタと参照式
- .や->の前後はスペースなし。
- *や&の後はスペースなし。
- ポインタ型の変数や引数を宣言する時はchar もchar cもあり。
- 複数変数の宣言: int x, y;はOKだがint x, *y;はNG。
boolean式
- 改行を入れるときは&&や||の位置は一貫させろ。行末に&&や||がくるのがgoogleでは一般的だが頭につけてもいい。
戻り値
- 無意味にreturnの中身を括弧で囲うな。(bad: return (value);)
変数やarrayの初期化
- int x=3;でもint x(3);でもint x{3};でもいい。
- 空でない{}を初期化に使うとstd::initializer_listを引数にとるコンストラクタが優先される。空の{}のときはデフォルトコンストラクタ優先。
- int pi(3.14);は勝手に丸められてしまうがint pi{3.14};はコンパイルエラーになるので安心。
プリプロセッサディレクティブ
- #ifとか行の先頭に。#のあとにスペースはいらない。周りのインデントに関わらずディレクティブは行頭から。
class
- public/protected/privateの行は1字下げ、セクション中身はもう1字下げ。
- 2つ目以降のpublic/protected/private行の手前は空行1つ(小さいクラスの場合はとばしてもいい)
- public/protected/privateの順
コンストラクタの初期化子列
- 同じ行に全部入れるか4字下げで改行。改行するなら:の手前で改行しろ。
namespace
- namespaceの{}内は字下げしない。
- 複数のnamespaceをネストするときはそれぞれ別の行に書く。
ホワイトスペース
- {}初期化子の{}の内側はスペースあってもなくてもいい。つけるなら両側に。
- {の前にはスペース
- class Foo : public Bar {...};の:の前後にはスペース
- 位置揃えのためのホワイトスペースはあり。
- 行の最後に空白はなし。
- for文の()中の;の後はスペース。
- レンジベースfor文の:の前後はスペース
- case文の:の前はスペースなし
- 代入演算子=の前後はスペース
- 二項演算子の前後にはスペースを普通入れるが項の中でスペースをなくすことはしていい
- 単項演算子とオペランドの間にはスペースを入れるな
- テンプレートの<>の中にはスペースなし
改行
- 不要に空行を入れるな。コードの"段落区切り"としてだけ使い、関数の頭や最後に空行を入れたりするな。
ルールの例外
- すでに存在しているルールに準拠しないコード
- windowsコード
最後に
- 一貫性を持たせろ。周囲のコードのスタイルに合わせろ。