Google C++ スタイルガイド 日本語全訳

C++ is one of the main development languages used by many of Google's open-source projects. C++は、多くのGoogleのオープンソースプロジェクトで採用されている主要言語のうちのひとつです。 As every C++ programmer knows, the language has many powerful features, but this power brings with it complexity, which in turn can make code more bug-prone and harder to read and maintain. C++プログラマーなら誰でも知っているように、この言語にはたくさんのパワフルな機能が備わっていますが、それと同時に非常に複雑でもあります。この複雑さこそが、ときにバグを埋め込む要因となったり、あるいは、コードを読みにくくメンテナンスしにくくしてしまう要因となったりしています。

The goal of this guide is to manage this complexity by describing in detail the dos and don'ts of writing C++ code. このガイドでは、C++のコードを書くときにすべきこと・すべきでないことを詳しく説明し、C++のもつ様々な複雑さに対処できるようにすることを目標としています。 These rules exist to keep the code base manageable while still allowing coders to use C++ language features productively. これらのルールに従えば、C++の生産的な言語機能を活かしつつ、コードベースを管理可能な状態に保つことができるでしょう。

Style, also known as readability, is what we call the conventions that govern our C++ code. スタイル」という語は、一般には可読性(readability/リーダビリティ)としても知られていますが、このガイドにおけるスタイルは、私たちのC++コードが従うべきコーディング規約全般のことを指しています。 The term Style is a bit of a misnomer, since these conventions cover far more than just source file formatting. これらの規約では、単なるソースコードのフォーマットにとどまらず、もっと広い範囲をカバーしていますので、その意味で、スタイルという用語を充てるのは少し語弊があるかもしれません。

Most open-source projects developed by Google conform to the requirements in this guide. ほとんどのGoogleのオープンソースプロジェクトが、このガイドの要件に沿って開発されています。

Note that this guide is not a C++ tutorial: we assume that the reader is familiar with the language. なお、このガイドはC++のチュートリアルではありません。むしろ、このガイドはC++に精通した読者に向けて書かれていますので、その点には注意してください。

このスタイルガイドのゴール

Why do we have this document? 何のために、この文書があるのでしょうか?

There are a few core goals that we believe this guide should serve. まず、このガイドが果たそうとする中心的な目標、すなわちゴールがいくつかあります。 These are the fundamental whys that underlie all of the individual rules. それらは、このガイドで説明されるすべての個別のルールの根底にある、基礎的な「なぜそのようにするのか」の集合です。 By bringing these ideas to the fore, we hope to ground discussions and make it clearer to our broader community why the rules are in place and why particular decisions have been made. 私たちは、これらの考え方を前面に出すことで、より広いコミュニティにおいて、議論を根付かせ、なぜそのルールがあるのか、なぜそのように決められているのか、より明確に理解されるようにしていきたいと考えています。 If you understand what goals each rule is serving, it should be clearer to everyone when a rule may be waived (some can be), and what sort of argument or alternative would be necessary to change a rule in the guide. このガイドで説明される各ルールの存在が、それぞれ何を達成しようとしているのか、その目的を正しく理解できれば、同時に、どのような場合にそのルールを放棄すべきか、あるいは、ルールを変更するために必要な議論や代替案についても、より考えやすくなることでしょう。

The goals of the style guide as we currently see them are as follows: 現時点での本スタイルガイドのゴールは以下のとおりです。

Style rules should pull their weight それぞれのスタイルルールが十分役立つものであること
The benefit of a style rule must be large enough to justify asking all of our engineers to remember it. 各スタイルルールがもたらす利益は、所属するすべてのエンジニアが覚えるに値するくらい、十分に価値のあるものでなければいけません。 The benefit is measured relative to the codebase we would get without the rule, so a rule against a very harmful practice may still have a small benefit if people are unlikely to do it anyway. ここでいう利益は「仮にそのルールが無かったとしたら、書かれてしまったかもしれないコード」との比較で計ります。 つまり、仮に何らかの非常に有害な慣行を制限するルールを考えたとしても、そもそもそのルールが無くても問題がない (すなわち、そのような有害な書き方は通常されない) のであれば、そのルールの価値は低いという風に考えます。 This principle mostly explains the rules we don’t have, rather than the rules we do: for example, goto contravenes many of the following principles, but is already vanishingly rare, so the Style Guide doesn’t discuss it. この原則は、むしろ、このスタイルガイドで取り扱わないルールについて説明していると言えます。 たとえば、このガイドではgotoの濫用に関するルールを取り扱っていません。gotoの濫用はこのガイドの多くの原則に違反しますが、昨今では、わざわざ禁止せずとも、gotoが濫用されること自体がほとんどなくなっているため、このルールを定めることにはあまり価値がありません。
Optimize for the reader, not the writer 書き手ではなく、読み手のためにコードを最適化すること
Our codebase (and most individual components submitted to it) is expected to continue for quite some time. 私たちのコードベース(と、それらに与する多くの個々のコンポーネント)は、今後、長い時を経ていきます。 As a result, more time will be spent reading most of our code than writing it. 結果的には、そのコードを書くのに費やした時間に比べ、はるかに多くの時間がコードを読むために割かれることでしょう。 We explicitly choose to optimize for the experience of our average software engineer reading, maintaining, and debugging code in our codebase rather than ease when writing said code. 私たちは、コードを書くときに楽をすることよりも、私たちの平均的なエンジニアにとって、コードが読みやすく、メンテしやすく、デバッグしやすくなるように最適化することを明示的に選択します。 "Leave a trace for the reader" is a particularly common sub-point of this principle: When something surprising or unusual is happening in a snippet of code (for example, transfer of pointer ownership), leaving textual hints for the reader at the point of use is valuable (std::unique_ptr demonstrates the ownership transfer unambiguously at the call site). 「コード読者のためのヒントを残すこと。」それがこの原則の共通のサブテーマです。コードの中で何か特殊なことをするとき(たとえば、ポインタの所有権を移すとき)、コード読者のためにコードを読み解くヒントを残すことは非常に価値のあることです。(たとえば、先ほどのポインタの所有権を移す例では、std::unique_ptrを使えば、曖昧性なくそのことを表現できるでしょう。)
Be consistent with existing code 既存のコードとの一貫性が保たれていること
Using one style consistently through our codebase lets us focus on other (more important) issues. ある唯一のスタイルをコードベース全体で一貫して用いることで、それ以外の、本来注目すべき重要な課題にフォーカスすることができます。 Consistency also allows for automation: tools that format your code or adjust your #includes only work properly when your code is consistent with the expectations of the tooling. また、一貫性を保つと、ツールによる自動化も進めやすくなります。たとえば、コード整形ツールや#includeを整理するツールは、コードがツールの期待と一貫しているときにのみ、その力を発揮することでしょう。 In many cases, rules that are attributed to "Be Consistent" boil down to "Just pick one and stop worrying about it"; the potential value of allowing flexibility on these points is outweighed by the cost of having people argue over them. 多くの場合において、「一貫性を保つ」に帰するルールは、「ある1つのやり方を選んで決め、それについて悩むのをやめる」ということに要約されます。これらの点では、多様性を認めることで得られる潜在的な価値よりも、それについて議論するコストの方が上回ってしまうからです。 However, there are limits to consistency; it is a good tie breaker when there is no clear technical argument, nor a long-term direction. ただし、「一貫性」には限度もあります。一貫性は、明確な技術的論拠や長期的な方向性等が特に無いときには、良い判断材料となります。 It applies more heavily locally (per file, or for a tightly-related set of interfaces). これは、局所的(ファイル単位、もしくは密に関連するインターフェース集合)なほど、より強く適用されます。 Consistency should not generally be used as a justification to do things in an old style without considering the benefits of the new style, or the tendency of the codebase to converge on newer styles over time. 一方で、新しいスタイルを採用するメリットや、時とともに新しいスタイルに移り変わっていくコードの傾向を考慮することなく、物事を古いスタイルのまま推し進めるための言い訳としては、「一貫性」を持ち出すべきではありません。
Be consistent with the broader C++ community when appropriate より広範囲なC++コミュニティとの一貫性を保つこと
Consistency with the way other organizations use C++ has value for the same reasons as consistency within our code base. 自分たちのコードベース内で一貫性を保つのと同じ理由で、C++を使う他の組織の手法との一貫性を保つことにも、やはり価値があります。 If a feature in the C++ standard solves a problem, or if some idiom is widely known and accepted, that's an argument for using it. ある課題に対してC++標準機能の範囲で目的を達成できるのならば、あるいは、あるイディオムが広く知られて受け入れられているのならば、その事実はそれらを採用する理由になるでしょう。 However, sometimes standard features and idioms are flawed, or were just designed without our codebase's needs in mind. しかし、しばしば、それらの標準機能やイディオムに不備があったり、あるいは、単に私たちのコードベースのニーズを満たさない設計になっていたりすることがあります。 In those cases (as described below) it's appropriate to constrain or ban standard features. 詳しくは後述しますが、このような場合には、それらの採用や使用について制限または禁止してしまう方が適切です。 In some cases we prefer a homegrown or third-party library over a library defined in the C++ Standard, either out of perceived superiority or insufficient value to transition the codebase to the standard interface. 場合によっては、C++標準ライブラリよりも自家製あるいはサードパーティのライブラリを選ぶこともあります。単にそれらのライブラリの方が優れている場合や、あるいは、コードベースを標準的なインターフェースに移行するほどに十分なメリットがないという場合などです。
Avoid surprising or dangerous constructs 特殊な構成・危険な構成を避けること
C++ has features that are more surprising or dangerous than one might think at a glance. C++の中には、一見しただけでは想像できない、驚くような挙動をするものや、あるいは危険な機能も存在しています。 Some style guide restrictions are in place to prevent falling into these pitfalls. 本ガイドでは、そのような落し穴を避けるために、いくつかの機能について使用制限を課すルールを設けています。 There is a high bar for style guide waivers on such restrictions, because waiving such rules often directly risks compromising program correctness. これらのルールを撤廃してしまうと、直接的にプログラムの正当性を損なってしまうリスクに晒されるため、そのような制限に関するルールの放棄については高いハードルがあります。
Avoid constructs that our average C++ programmer would find tricky or hard to maintain 平均的なC++プログラマーがトリッキーに感じたり、あるいはメンテナンスしにくいと感じたりする可能性のある構成を避けること
C++ has features that may not be generally appropriate because of the complexity they introduce to the code. C++の中には、その機能によってコードが複雑化してしまうのを避けるため、通常は採用すべきでないような機能も存在します。 In widely used code, it may be more acceptable to use trickier language constructs, because any benefits of more complex implementation are multiplied widely by usage, and the cost in understanding the complexity does not need to be paid again when working with new portions of the codebase. とはいえ、広く使われるコードであれば、多少トリッキーな言語構造をしていても、比較的受け入れられやすい場合もあります。その複雑な実装が広く使われることによって価値が倍増し、また、新たなコード中で再度その実装を扱うときには、その複雑さに対する学習コストを再度支払う必要がなくなっているためです。 When in doubt, waivers to rules of this type can be sought by asking your project leads. これについて迷ったときは、この種のルールの放棄について、プロジェクトリーダーと相談してください。 This is specifically important for our codebase because code ownership and team membership changes over time: even if everyone that works with some piece of code currently understands it, such understanding is not guaranteed to hold a few years from now. このことは、私たちのコードベースでは特に重要です。なぜなら、コードの担当者やチームのメンバーは時とともに変化していくからです。たとえ今この瞬間に、チームメンバー全員が全てのコードを理解できていたとしても、数年後も同じである保証はどこにもありません。
Be mindful of our scale 私たち自身の規模に留意すること
With a codebase of 100+ million lines and thousands of engineers, some mistakes and simplifications for one engineer can become costly for many. 1億行以上のコードがあり、何千人ものエンジニアが働くコードベースにおいては、ある1人のミスや単純化が、多くのエンジニアの損失を招くことがあります。 For instance it's particularly important to avoid polluting the global namespace: name collisions across a codebase of hundreds of millions of lines are difficult to work with and hard to avoid if everyone puts things into the global namespace. たとえば、グローバル名前空間の汚染を避けることは非常に重要です。何億行ものコードベースにおいて、誰もがグローバル名前空間に何でもかんでも入れていたら、名前の衝突を避けるのは困難を極めるでしょう。
Concede to optimization when necessary 必要な最適化は容認すること
Performance optimizations can sometimes be necessary and appropriate, even when they conflict with the other principles of this document. しばしば、パフォーマンス上の最適化を必要とする場合があります。たとえ、本ガイドの何らかのルールと競合したとしても、そのパフォーマンスの最適化が必要かつ適切なのであれば、それを行ってください。

The intent of this document is to provide maximal guidance with reasonable restriction. このドキュメントの趣旨は、合理的な制限を設けて、最大限の道しるべを提供することにあります。 As always, common sense and good taste should prevail. いつもどおり、常識と良識を優先してください。 By this we specifically refer to the established conventions of the entire Google C++ community, not just your personal preferences or those of your team. これは特に、個人やチームの好みに限らず、GoogleのC++コミュニティ全体で確立された慣習を指しています。 Be skeptical about and reluctant to use clever or unusual constructs: the absence of a prohibition is not the same as a license to proceed. 巧妙(clever)な構成や特殊な構成に対して懐疑的な姿勢を持ち、それらを避けるようにしてください。禁止されていなければやってもよいというわけではありません。 Use your judgment, and if you are unsure, please don't hesitate to ask your project leads to get additional input. 自らで判断しましょう。もし確信を持てないときは、遠慮なくプロジェクトリーダーに質問して、さらなるインプットを得るようにしてください。

C++のバージョン

Currently, code should target C++20, i.e., should not use C++23 features. 現時点において、コードはC++20をターゲットとします。C++23の機能は使ってはいけません。 The C++ version targeted by this guide will advance (aggressively) over time. なお、このガイドが対象とするC++のバージョンは、時とともに(かつ積極的に)進行します。

Do not use non-standard extensions. 非標準の拡張を使ってはいけません。

Consider portability to other environments before using features from C++17 and C++20 in your project. C++17やC++20から導入された比較的新しい機能については、それらを使う前に、他の環境への移植性について考慮してください。

ヘッダーファイル

In general, every .cc file should have an associated .h file. 一般的に、全ての.ccファイルについて、それと対応する.hファイルを作るようにします。 There are some common exceptions, such as unit tests and small .cc files containing just a main() function. ただし、ユニットテストやmain()だけを含むような小さな.ccファイルは例外としてもかまいません。

Correct use of header files can make a huge difference to the readability, size and performance of your code. 正しくヘッダーファイルを扱うことは、コードの可読性やサイズ、パフォーマンスに大きな違いをもたらします。

The following rules will guide you through the various pitfalls of using header files. 以下に続くルールは、ヘッダーファイルに関する様々な落とし穴を避けるためのガイドとなるでしょう。

自己完結ヘッダー

Header files should be self-contained (compile on their own) and end in .h. ヘッダーファイルは、自己完結、すなわち、それ単体でコンパイルできるようにします。また、ファイル名は.hで終わります。 Non-header files that are meant for inclusion should end in .inc and be used sparingly. ヘッダーファイル以外で#includeされることを意図したファイルには.incで終わる名前を付けます。ただし、なるべく使用を控えるようにしましょう。

All header files should be self-contained. すべてのヘッダーファイルは自己完結、すなわち、それ単体でコンパイルできるようになっていなければなりません。 Users and refactoring tools should not have to adhere to special conditions to include the header. ヘッダーファイルの利用者やリファクタリングツールに対して、そのヘッダーを#includeする際の事前条件を何ら課さないようにしてください。 Specifically, a header should have header guards and include all other headers it needs. すなわち、ヘッダーにはインクルードガードを書き、そのヘッダーが必要とする他のヘッダーをすべて#includeしてください。

When a header declares inline functions or templates that clients of the header will instantiate, the inline functions and templates must also have definitions in the header, either directly or in files it includes. あるヘッダーファイルにおいて、利用者に向けたインライン関数やテンプレートを宣言するときは、それらの定義も、同一のヘッダーファイル内か、同一ヘッダーファイルから#includeするファイルの中に含めてください。 Do not move these definitions to separately included header (-inl.h) files; this practice was common in the past, but is no longer allowed. これらの定義を、別途#includeされるヘッダーファイル (-inl.h) に移動してはいけません。この手法は、過去には慣習的でしたが、現在では許容されません。 When all instantiations of a template occur in one .cc file, either because they're explicit or because the definition is accessible to only the .cc file, the template definition can be kept in that file. また、あるテンプレートのインスタンス化が特定の単一の.ccファイル内でのみ行われる場合には、そのテンプレートの定義を.ccファイルの中に保持してもかまいません。これは、たとえば明示的なテンプレートのインスタンス化を行う場合や、あるいは、テンプレートの定義へのアクセスをその.ccファイルからのみに限定している場合などがあてはまります。

There are rare cases where a file designed to be included is not self-contained. レアケースながら、#includeされることを目的としつつも、自己完結でないファイルも存在します。 These are typically intended to be included at unusual locations, such as the middle of another file. これらのファイルは、典型的には、別のファイルの中ほどなどの特殊な場所で#includeされることを意図して作られており、 They might not use header guards, and might not include their prerequisites. その内容としてインクルードガードを持っていなかったり、そのヘッダーが必要とする他のファイルを#includeしていなかったりします。 Name such files with the .inc extension. このようなファイルには、.inc拡張子で終わるファイル名をつけてください。 Use sparingly, and prefer self-contained headers when possible. ただし、なるべく使用するのを控え、可能な限り自己完結ヘッダーを用いるようにしてください。

インクルードガード

All header files should have #define guards to prevent multiple inclusion. 多重にインクルードされるのを防ぐために、すべてのヘッダーファイルにおいて、インクルードガード(#defineによるガード)を持たせます。 The format of the symbol name should be <PROJECT>_<PATH>_<FILE>_H_. ガードのシンボル名は<PROJECT>_<PATH>_<FILE>_H_の形式とします。

To guarantee uniqueness, they should be based on the full path in a project's source tree. ユニーク性を保証するため、インクルードガードのシンボル名は、プロジェクト内ソースツリー上のフルパスに基づくものをつけてください。 For example, the file foo/src/bar/baz.h in project foo should have the following guard: たとえば、プロジェクトfooに含まれるファイルfoo/src/bar/baz.hのインクルードガードは次のようにします。

#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_

...

#endif  // FOO_BAR_BAZ_H_

必要なものを#includeする

If a source or header file refers to a symbol defined elsewhere, the file should directly include a header file which properly intends to provide a declaration or definition of that symbol. ソースファイル上やヘッダーファイル上において、何らか他の場所で定義されたシンボルを参照したいときは、そのシンボルの宣言・定義の提供を意図されたヘッダーファイルを直接#includeします。 It should not include header files for any other reason. そして、それ以外の理由では#includeしてはいけません。

Do not rely on transitive inclusions. 推移的な#includeに頼ってはいけません。 This allows people to remove no-longer-needed #include statements from their headers without breaking clients. 推移的な#includeが禁止されているのであればこそ、ヘッダーファイルの著者は、ユーザーのコードを破壊することなく、安心して、不要となった#include文を削除できるようになります。 This also applies to related headers - foo.cc should include bar.h if it uses a symbol from it even if foo.h includes bar.h. なお、このルールは、先の「.ccに対応するヘッダー」にも適用されます。 foo.ccbar.hのシンボルを使うのであれば、たとえ既にfoo.h#include "bar.h"していたとしても、改めてfoo.ccでも#include "bar.h"してください。

前方宣言

Avoid using forward declarations where possible. 前方宣言は、可能な限り避けます。 Instead, include the headers you need. かわりに必要なヘッダーを#includeします。

A "forward declaration" is a declaration of an entity without an associated definition. 「前方宣言」とは、対応する定義のないエンティティの宣言のことです。

// In a C++ source file:
class B;
void FuncInB();
extern int variable_in_b;
ABSL_DECLARE_FLAG(flag_in_b);
// C++ソース内:
class B;
void FuncInB();
extern int variable_in_b;
ABSL_DECLARE_FLAG(flag_in_b);

インライン関数

Define functions inline only when they are small, say, 10 lines or fewer. インライン関数は、関数定義が小さいとき(10行以下程度)に限ります。

You can declare functions in a way that allows the compiler to expand them inline rather than calling them through the usual function call mechanism. 関数は、通常の関数呼び出しのかわりに、コンパイラによって直接その場にインライン展開されることを許す形でも宣言することができます。

Inlining a function can generate more efficient object code, as long as the inlined function is small. 関数が十分に小さいとき、インライン化によって、より効率的なオブジェクトコードを生成できます。 Feel free to inline accessors and mutators, and other short, performance-critical functions. たとえば、getter関数(原: accessors)、setter関数(原: mutators)、あるいは、その他の短く、かつパフォーマンスクリティカルな関数は自由にインライン化してかまいません。

Overuse of inlining can actually make programs slower. インライン関数を濫用すると、逆にプログラムの動作が遅くなってしまうことがあります。 Depending on a function's size, inlining it can cause the code size to increase or decrease. 関数をインライン化すると、対象の関数のサイズによって、インライン化後のコードサイズが増減します。 Inlining a very small accessor function will usually decrease code size while inlining a very large function can dramatically increase code size. 非常に小さなgetter関数などをインライン化する分には、通常はコード全体のサイズが小さくなりますが、しかし、非常に大きな関数をインライン化してしまうと、コード全体のサイズが劇的に大きくなってしまうことがあります。 On modern processors smaller code usually runs faster due to better use of the instruction cache. 現代的なCPUにおいては、一般に、コードサイズが小さい方が、命令キャッシュを有効に使えるため、高速に動作します。

A decent rule of thumb is to not inline a function if it is more than 10 lines long. 経験則として、関数が10行より長くなったらインライン化すべきではありません。 Beware of destructors, which are often longer than they appear because of implicit member- and base-destructor calls! また、デストラクタには特に注意が必要です。デストラクタは、暗黙的にメンバのデストラクタと基底クラスのデストラクタを呼び出すため、その見た目に比べて長い実体を持つことがあります。

Another useful rule of thumb: it's typically not cost effective to inline functions with loops or switch statements (unless, in the common case, the loop or switch statement is never executed). もうひとつの経験則として、ループやswitch文を含む関数は、(それらの文がまったく実行されないような場合を除いて)大抵の場合、インライン化しても効率的になりません。

It is important to know that functions are not always inlined even if they are declared as such; for example, virtual and recursive functions are not normally inlined. なお、注意点として、関数をインラインに宣言したとしても、あくまでインライン化を許すだけであって、必ずインライン化されるわけではありません。たとえば、仮想関数や再帰関数は通常はインライン化されません。 Usually recursive functions should not be inline. 通常、再帰関数はインラインにすべきではありません。 The main reason for making a virtual function inline is to place its definition in the class, either for convenience or to document its behavior, e.g., for accessors and mutators. 仮想関数をクラス内にインライン定義する主な理由は、利便性や、あるいは、(たとえば、getterやsetterなどの場合に)その挙動に関するドキュメントとしての役割を持たせられることにあります。

#includeの名前と順序

Include headers in the following order: Related header, C system headers, C++ standard library headers, other libraries' headers, your project's headers. #includeは次の順番で行います: .cc自身と対応するヘッダー、C言語のシステムヘッダー、C++標準ライブラリヘッダー、その他のライブラリのヘッダー、自分のプロジェクト内のヘッダー。

All of a project's header files should be listed as descendants of the project's source directory without use of UNIX directory aliases . (the current directory) or .. (the parent directory). すべてのプロジェクトヘッダーのパスは、プロジェクトのソースディレクトリのルートからの相対パスで記述します。その際、UNIXディレクトリのエイリアスである./(カレントディレクトリ)や、../(親ディレクトリ)は省きます。 For example, google-awesome-project/src/base/logging.h should be included as: たとえば、google-awesome-project/src/base/logging.h#include文は次のようにします。

#include "base/logging.h"

In dir/foo.cc or dir/foo_test.cc, whose main purpose is to implement or test the stuff in dir2/foo2.h, order your includes as follows: #includeの順序の例として、たとえばdir/foo.hの宣言を実装するファイルdir/foo.ccや、もしくは、それらをテストする目的のファイルdir/foo_test.ccにおいては、次の順に並べます。

  1. dir2/foo2.h. dir/foo.h (対応するヘッダーファイル)
  2. A blank line 空行
  3. C system headers (more precisely: headers in angle brackets with the .h extension), e.g., <unistd.h>, <stdlib.h>. C言語のシステムヘッダー(より正確には、<>で囲まれ、拡張子.hを持つもの)、たとえば<unistd.h><stdlib.h>
  4. A blank line 空行
  5. C++ standard library headers (without file extension), e.g., <algorithm>, <cstddef>. C++標準ライブラリのヘッダー(拡張子のないもの)、たとえば<algorithm><cstddef>など
  6. A blank line 空行
  7. Other libraries' .h files. 他のライブラリの.hファイル
  8. A blank line 空行
  9. Your project's .h files. 自分のプロジェクトの.hファイル

Separate each non-empty group with one blank line. 空でないグループ同士の間には空行を1つ入れます。

With the preferred ordering, if the related header dir2/foo2.h omits any necessary includes, the build of dir/foo.cc or dir/foo_test.cc will break. この順番にしておくと、.ccの対応ヘッダーdir/foo.hで必要なインクルードを忘れてしまったときに、まずdir/foo.ccdir/foo_test.ccのコンパイルが失敗します。 Thus, this rule ensures that build breaks show up first for the people working on these files, not for innocent people in other packages. これによって、ビルドが壊れたときに、他のパッケージで作業している無実の人ではなく、当該ファイルで作業をしていた本人が最初に気づくことができるようになります。

dir/foo.cc and dir2/foo2.h are usually in the same directory (e.g., base/basictypes_test.cc and base/basictypes.h), but may sometimes be in different directories too. dir/foo.ccdir/foo.hは、通常は同じディレクトリ内に置きます(たとえば、base/basictypes_test.ccbase/basictypes.hも同様です)が、必要に応じて異なるディレクトリに置いてもかまいません。

Note that the C headers such as stddef.h are essentially interchangeable with their C++ counterparts (cstddef). なお、stddef.hのようなC言語のヘッダーは、C++の相当するヘッダー(cstddef)と相互に置き換えることができます。 Either style is acceptable, but prefer consistency with existing code. どちらのスタイルでもかまいませんが、既存のコードとの一貫性を優先してください。

Within each section the includes should be ordered alphabetically. 各セクション内ではアルファベット順に並べます。 Note that older code might not conform to this rule and should be fixed when convenient. 古いコードではそうなっていないことがありますが、修正したほうが都合がよければ、修正してしまいましょう。

For example, the includes in google-awesome-project/src/foo/internal/fooserver.cc might look like this: 全体の例として、たとえば、google-awesome-project/src/foo/internal/fooserver.cc#includeは次のようになります。

#include "foo/server/fooserver.h"

#include <sys/types.h>
#include <unistd.h>

#include <string>
#include <vector>

#include "base/basictypes.h"
#include "foo/server/bar.h"
#include "third_party/absl/flags/flag.h"

Sometimes, system-specific code needs conditional includes. システム特有のコードは、しばしば条件付きの#includeを必要とする場合があります。 Such code can put conditional includes after other includes. そのような条件付き#includeは、それ以外の#includeの後に配置します。 Of course, keep your system-specific code small and localized. もちろんのことですが、システム特有のコードは小さく局所的に保つようにしてください。 Example: 次に例を示します。

#include "foo/public/fooserver.h"

#include "base/port.h"  // For LANG_CXX11.

#ifdef LANG_CXX11
#include <initializer_list>
#endif  // LANG_CXX11

スコープ

名前空間

With few exceptions, place code in a namespace. 一部の例外を除いて、コードは何らかの名前空間の中に置きます。 Namespaces should have unique names based on the project name, and possibly its path. 名前空間にはプロジェクト名やファイルパスに基づくユニークな名前をつけます。 Do not use using-directives (e.g., using namespace foo). usingディレクティブ(using namespace foo)は使ってはいけません。 Do not use inline namespaces. インライン名前空間を使ってはいけません。 For unnamed namespaces, see Internal Linkage. 無名名前空間については内部リンケージを参照してください。

Namespaces subdivide the global scope into distinct, named scopes, and so are useful for preventing name collisions in the global scope. 名前空間によって、グローバルスコープを異なる名前付きのスコープに分割できます。これによって、グローバルスコープにおける名前の衝突を防ぐことができます。

Namespaces provide a method for preventing name conflicts in large programs while allowing most code to use reasonably short names. 名前空間を用いると、大きなプログラムであっても、コードの大部分において合理的な短い名前を使いながら、全体として名前の衝突を防ぐことができます。

For example, if two different projects have a class Foo in the global scope, these symbols may collide at compile time or at runtime. たとえば、2つの異なるプロジェクトにおいて同じ名前のクラスFooがグローバル名前空間に含まれていたとすると、これらのシンボルはコンパイル時や実行時に衝突してしまいます。 If each project places their code in a namespace, project1::Foo and project2::Foo are now distinct symbols that do not collide, and code within each project's namespace can continue to refer to Foo without the prefix. もし、それぞれのプロジェクトがそれらのクラスをプロジェクト独自の名前空間の中に入れていたならば、project1::Fooproject2::Fooとは区別できるようになり、衝突することはなくなります。しかも、各プロジェクトの名前空間内では、引き続き、接頭辞なしのただのFooという名前で、そのクラスを参照することができます。

Inline namespaces automatically place their names in the enclosing scope. インライン名前空間は、自身の名前を自動的に外側のスコープに配置します。 Consider the following snippet, for example: 例として、次のスニペットについて考えます。

namespace outer {
inline namespace inner {
  void foo();
}  // namespace inner
}  // namespace outer

The expressions outer::inner::foo() and outer::foo() are interchangeable. このとき、式outer::inner::foo()outer::foo()とは相互に交換可能です。 Inline namespaces are primarily intended for ABI compatibility across versions. インライン名前空間は、主にバージョン間におけるABIの互換性を保つことを目的として利用することができます。

Namespaces can be confusing, because they complicate the mechanics of figuring out what definition a name refers to. 名前空間は、名前から定義を解決する仕組みをより複雑化させるため、困惑を招くことがあります。

Inline namespaces, in particular, can be confusing because names aren't actually restricted to the namespace where they are declared. 特にインライン名前空間は、事実上、その中で宣言される名前を名前空間の中に閉じ込めないため困惑の元となりやすいです。 They are only useful as part of some larger versioning policy. インライン名前空間は、バージョン管理ポリシーの一部としてのみ役に立ちます。

In some contexts, it's necessary to repeatedly refer to symbols by their fully-qualified names. また、文脈によっては、完全修飾された名前を用いて繰り返しシンボルを参照する必要に迫られることがあります。 For deeply-nested namespaces, this can add a lot of clutter. このとき、名前空間のネストが深いと、コードが散らかってしまいます。

Namespaces should be used as follows: 名前空間は次のように使いましょう。

内部リンケージ

When definitions in a .cc file do not need to be referenced outside that file, give them internal linkage by placing them in an unnamed namespace or declaring them static. エンティティの定義が.ccファイル内にあり、かつ、ファイル外から参照される必要がないときは、それらを無名の名前空間内に置くか、もしくはstaticに宣言することによって、内部リンケージとなるようにします。 Do not use either of these constructs in .h files. なお、.hファイル内では、これらのいずれも行ってはいけません。

All declarations can be given internal linkage by placing them in unnamed namespaces. 無名名前空間内で宣言を行うことによって、それらを内部リンケージとすることができます。 Functions and variables can also be given internal linkage by declaring them static. 関数と変数は、staticに宣言することでも、内部リンケージにすることができます。 This means that anything you're declaring can't be accessed from another file. 内部リンケージのエンティティは他のファイルからアクセスできなくなります。 If a different file declares something with the same name, then the two entities are completely independent. また、仮に、異なるファイル間において同名のエンティティが宣言されていたとしても、それらは完全に独立した別の実体として扱われることになります。

Use of internal linkage in .cc files is encouraged for all code that does not need to be referenced elsewhere. 他の場所から参照される必要のないすべてのコードを、.cc内の内部リンケージにすることを推奨します。 Do not use internal linkage in .h files. .hファイルでは内部リンケージは使用してはいけません。

Format unnamed namespaces like named namespaces. 無名名前空間も、名前付きの名前空間と同じようにフォーマットしてください。 In the terminating comment, leave the namespace name empty: 無名名前空間が終わるときのコメントは、次のように、名前空間名を空白のままにしたものを記述してください。

namespace {
...
}  // namespace

非メンバ関数、静的メンバ関数、グローバル関数

Prefer placing nonmember functions in a namespace; use completely global functions rarely. 非メンバ関数(すなわち通常の関数)は何らかの名前空間内に置きます。完全なグローバル関数はまず使いません。 Do not use a class simply to group static members. 静的メンバを単にグループ化する目的でクラスを作ってはいけません。 Static methods of a class should generally be closely related to instances of the class or the class's static data. 静的メンバ関数は、そのクラスのインスタンスや静的データと強い関連がある場合に限って使用します。

Nonmember and static member functions can be useful in some situations. 非メンバ関数や静的メンバ関数は、様々な場面で有用です。 Putting nonmember functions in a namespace avoids polluting the global namespace. 非メンバ関数は何らかの名前空間内に置くことで、グローバル名前空間の汚染を避けられます。

Nonmember and static member functions may make more sense as members of a new class, especially if they access external resources or have significant dependencies. 非メンバ関数や静的メンバ関数は、新しいクラスのメンバとした方が合理的な場合があります。特に、それらが外部のリソースにアクセスしていたり、あるいは強く依存していたりする場合などです。

Sometimes it is useful to define a function not bound to a class instance. 場合によって、いずれのクラスインスタンスにも紐付かない関数を定義する方が都合が良いことがあります。 Such a function can be either a static member or a nonmember function. このような関数は、静的メンバ関数や非メンバ関数(通常の関数)のいずれかとすることができます。 Nonmember functions should not depend on external variables, and should nearly always exist in a namespace. 非メンバ関数を定義する場合、それらは外部の変数に依存すべきではありません。また、ほとんど常に名前空間の中におかれなければなりません。 Do not create classes only to group static members; this is no different than just giving the names a common prefix, and such grouping is usually unnecessary anyway. 単に静的なメンバをグループ化するためだけの目的でクラスを作ってはいけません。 このようなクラスを作ることは、名前に共通の接頭辞をつけることと何ら違いがありませんし、そもそも、通常はそのようなグループ化を行うこと自体が不要なはずです。

If you define a nonmember function and it is only needed in its .cc file, use internal linkage to limit its scope. また、非メンバ関数を定義する場合で、かつ、その関数が特定の.ccファイル内からのみ必要とされる場合には、そのスコープを制限するために内部リンケージを使用してください。

ローカル変数

Place a function's variables in the narrowest scope possible, and initialize variables in the declaration. 関数内の変数宣言は、可能な限りそのスコープを狭くします。また、変数は宣言と同時に初期化します。

C++ allows you to declare variables anywhere in a function. C++では、関数内のどこでも変数を宣言することができます。 We encourage you to declare them in a scope as local as possible, and as close to the first use as possible. 変数は、できる限り局所的なスコープの中で、また、できる限り初めて使う場所の近くで宣言することが望ましいです。 This makes it easier for the reader to find the declaration and see what type the variable is and what it was initialized to. そうしておくことで、コードの読者が変数宣言を見つけやすくなり、変数の型や初期化の方法についての見通しがよくなります。 In particular, initialization should be used instead of declaration and assignment, e.g.,: また、変数は、変数宣言と代入を別々に行うのではなく、宣言と同時に初期化するようにしてください。以下に例を示します。

int i;
i = f();      // Bad -- initialization separate from declaration.
int i;
i = f();      // 悪い例。初期化が宣言と分かれています。
int i = f();  // Good -- declaration has initialization.
int i = f();  // 良い例。宣言と同時に初期化が行われています。
int jobs = NumJobs();
f(jobs);      // Good -- declaration immediately (or closely) followed by use.
int jobs = NumJobs();
f(jobs);      // 良い例。使用する直前に(あるいはすぐ近くで)宣言されています。
std::vector<int> v;
v.push_back(1);  // Prefer initializing using brace initialization.
v.push_back(2);
std::vector<int> v;
v.push_back(1);  // {}による初期化を使う方が望ましいです。
v.push_back(2);
std::vector<int> v = {1, 2};  // Good -- v starts initialized.
std::vector<int> v = {1, 2};  // 良い例。宣言と同時に初期化されています。

Variables needed for if, while and for statements should normally be declared within those statements, so that such variables are confined to those scopes. E.g.,: if文やwhile文、for文で使用される変数は、通常はそれらの文中で宣言します。そうすることで、変数のスコープを制限できます。 以下に例を示します。

while (const char* p = strchr(str, '/')) str = p + 1;

There is one caveat: if the variable is an object, its constructor is invoked every time it enters scope and is created, and its destructor is invoked every time it goes out of scope. ただし、変数がオブジェクト型であるときは少し注意が必要です。スコープ内で変数を宣言した場合、スコープに入るたびに毎回コンストラクタが呼ばれ、オブジェクトが生成され、スコープから出るたびに毎回デストラクタが呼ばれることになります。

// Inefficient implementation:
for (int i = 0; i < 1000000; ++i) {
  Foo f;  // My ctor and dtor get called 1000000 times each.
  f.DoSomething(i);
}
// 非効率的な実装
for (int i = 0; i < 1000000; ++i) {
  Foo f;  // コンストラクタとデストラクタがそれぞれ 1000000 回呼ばれます。
  f.DoSomething(i);
}

It may be more efficient to declare such a variable used in a loop outside that loop: このような場合、変数宣言をループの外側に出すことで、より効率的にできる場合があります。

Foo f;  // My ctor and dtor get called once each.
for (int i = 0; i < 1000000; ++i) {
  f.DoSomething(i);
}
Foo f;  // コンストラクタとデストラクタが1回だけ呼ばれます。
for (int i = 0; i < 1000000; ++i) {
  f.DoSomething(i);
}

静的変数とグローバル変数

Objects with static storage duration are forbidden unless they are trivially destructible. 静的記憶域期間(static storage duration)」を持つオブジェクトは、それらが「自明に破壊可能(trivially destructible)」でない限り禁止します。 Informally this means that the destructor does not do anything, even taking member and base destructors into account. 「自明に破壊可能」とは、ざっくり言うと、そのメンバ変数や基底クラスのデストラクタまで含めて、デストラクタが一切何もしないということを意味します。 More formally it means that the type has no user-defined or virtual destructor and that all bases and non-static members are trivially destructible. より正式には、型にユーザー定義デストラクタまたは仮想デストラクタがなく、かつ、すべての基底クラスと非静的メンバもまた同様に自明に破壊可能であるときに「自明に破壊可能」が成り立ちます。 Static function-local variables may use dynamic initialization. 関数ローカルスコープの静的変数は、動的初期化を行ってもかまいません。 Use of dynamic initialization for static class member variables or variables at namespace scope is discouraged, but allowed in limited circumstances; see below for details. それ以外の、クラススコープの静的メンバ変数や名前空間スコープの静的変数については、動的初期化を行うことは原則として非推奨です。ただし、後述するいくつかの限定された状況においては、使用が認められることもあります。

As a rule of thumb: a global variable satisfies these requirements if its declaration, considered in isolation, could be constexpr. 大雑把な判断基準として、グローバル変数については、その宣言が他に独立してconstexprにできるとき、これらの要件を満たしていると言えます。

Every object has a storage duration, which correlates with its lifetime. すべてのオブジェクトには記憶域期間(storage duration)があり、その寿命と関連しています。 Objects with static storage duration live from the point of their initialization until the end of the program. 静的記憶域期間を持つオブジェクトは、それらが初期化された時点からプログラムの終了までの寿命を持ちます。 Such objects appear as variables at namespace scope ("global variables"), as static data members of classes, or as function-local variables that are declared with the static specifier. これらのオブジェクトは、名前空間スコープの変数(いわゆるグローバル変数)や、クラスの静的データメンバ変数、あるいは、static指定子つきで宣言される関数ローカル変数として現れます。 Function-local static variables are initialized when control first passes through their declaration; all other objects with static storage duration are initialized as part of program start-up. 関数ローカルの静的変数は、プログラムの処理が初めてその宣言を通過するときに初期化されますが、それ以外の静的オブジェクトは、プログラムの起動処理の一環として初期化されることになります。 All objects with static storage duration are destroyed at program exit (which happens before unjoined threads are terminated). 静的記憶域期間を持つすべてのオブジェクトは、プログラムの終了時に破壊されます。この破壊処理は、プログラムの終了時に待機(join)されていないスレッドが存在する場合、それらのスレッドが強制終了されるよりもに行われるため、注意が必要です。

Initialization may be dynamic, which means that something non-trivial happens during initialization. これらの変数は動的(dynamic)に初期化することもできますが、そのような初期化においては自明ではないことが起こるかもしれません。 (For example, consider a constructor that allocates memory, or a variable that is initialized with the current process ID.) (たとえば、メモリを割り当てるコンストラクタの実行や、現在のプロセスIDによって初期化される変数などがこれに当てはまります。) The other kind of initialization is static initialization. また、これとは別の初期化の種類として静的(static)初期化があります。 The two aren't quite opposites, though: static initialization always happens to objects with static storage duration (initializing the object either to a given constant or to a representation consisting of all bytes set to zero), whereas dynamic initialization happens after that, if required. これら2つの初期化は完全に相反するわけではありません。 静的初期化は、すべての静的記憶域期間を持つオブジェクトにおいて必ず発生します。(オブジェクトは、初期化子に与えられた何らかの定数や、あるいはゼロで埋めることによって初期化されます。) そして、その後で、必要に応じて動的初期化が行われます。

Global and static variables are very useful for a large number of applications: named constants, auxiliary data structures internal to some translation unit, command-line flags, logging, registration mechanisms, background infrastructure, etc. グローバル変数と静的変数は様々な用途で有用です。その用途は、たとえば、名前付きの定数、翻訳単位内部の補助的データ構造、コマンドラインフラグ、ログ出力、登録メカニズム、バックグラウンドインフラストラクチャなど、多岐にわたり、多数のアプリケーションで非常に役立ちます。

Global and static variables that use dynamic initialization or have non-trivial destructors create complexity that can easily lead to hard-to-find bugs. 動的初期化や非自明(non-trivial)なデストラクタを持つグローバル変数や静的変数は、プログラムを複雑化させ、容易に発見困難なバグを引き起こします。 Dynamic initialization is not ordered across translation units, and neither is destruction (except that destruction happens in reverse order of initialization). 静的記憶域期間を持つ変数の動的初期化は、翻訳単位間をまたいだ順序付けが行われません。また、それらが破壊される順序も(初期化の逆順で行われるという点を除けば)同様です。 When one initialization refers to another variable with static storage duration, it is possible that this causes an object to be accessed before its lifetime has begun (or after its lifetime has ended). このため、ある変数の初期化処理(あるいは破壊処理)において、他の静的記憶域期間を持つ変数を参照していると、そのオブジェクトが初期化される前(あるいは寿命が終わった後)にそのオブジェクトにアクセスしてしまう恐れがあります。 Moreover, when a program starts threads that are not joined at exit, those threads may attempt to access objects after their lifetime has ended if their destructor has already run. さらに、プログラムが実行中に何らかのスレッドを起動していて、プログラム終了時にそれらを待機(join)しなかった場合、それらのスレッドから、既にデストラクタが実行され寿命が終わったオブジェクトへのアクセスを試みてしまうかもしれません。

破壊に関する結論

When destructors are trivial, their execution is not subject to ordering at all (they are effectively not "run"); otherwise we are exposed to the risk of accessing objects after the end of their lifetime. デストラクタが自明(trivial)な場合、それらの実行は順序付けの議論の対象とはなりません (そもそも、これらのオブジェクトのデストラクタには、実質的に「実行される処理」がありません)。しかし、非自明なデストラクタを持つオブジェクトを静的変数とした場合には、潜在的に、寿命が終わった後のオブジェクトにアクセスしてしまう危険性を抱え込むことになります。 Therefore, we only allow objects with static storage duration if they are trivially destructible. したがって、オブジェクトを静的記憶域期間としても良い条件として、少なくともそれらが「自明に破壊可能(trivially destructible)」である場合にのみ認めることとします。 Fundamental types (like pointers and int) are trivially destructible, as are arrays of trivially destructible types. 基本的な組み込みの型(ポインタやintなど)は自明に破壊可能であり、自明に破壊可能な型の配列も同様に自明に破壊可能です。 Note that variables marked with constexpr are trivially destructible. また、これらに加えてconstexprでマークされた変数も自明に破壊可能となりますので、この点は覚えておくとよいでしょう。

const int kNum = 10;  // Allowed

struct X { int n; };
const X kX[] = {{1}, {2}, {3}};  // Allowed

void foo() {
  static const char* const kMessages[] = {"hello", "world"};  // Allowed
}

// Allowed: constexpr guarantees trivial destructor.
constexpr std::array<int, 3> kArray = {1, 2, 3};
const int kNum = 10;  // OK

struct X { int n; };
const X kX[] = {{1}, {2}, {3}};  // OK

void foo() {
  static const char* const kMessages[] = {"hello", "world"};  // OK
}

// OK: constexpr は trivial destructor を保証する。
constexpr std::array<int, 3> kArray = {1, 2, 3};
// Bad: non-trivial destructor
const std::string kFoo = "foo";

// Bad for the same reason, even though kBar is a reference (the
// rule also applies to lifetime-extended temporary objects).
const std::string& kBar = StrCat("a", "b", "c");

void bar() {
  // Bad: non-trivial destructor.
  static std::map<int, int> kData = {{1, 0}, {2, 0}, {3, 0}};
}
// ダメ: non-trivial destructor
const std::string kFoo = "foo";

// 同様の理由でダメ。kBarが参照であったとしても。
// このルールは、一時オブジェクトの有効期限の延長が行われた場合も対象。
const std::string& kBar = StrCat("a", "b", "c");

void bar() {
  // ダメ: non-trivial destructorを持つ
  static std::map<int, int> kData = {{1, 0}, {2, 0}, {3, 0}};
}

Note that references are not objects, and thus they are not subject to the constraints on destructibility. なお、参照はオブジェクトそのものではないため、破壊可能性に関する制約も受けません。 The constraint on dynamic initialization still applies, though. (ただし、その場合であっても、動的初期化に関する制約はそのまま適用されます。) In particular, a function-local static reference of the form static T& t = *new T; is allowed. 特に、static T& t = *new T; のような形の関数ローカルの静的参照変数は問題ありません。

初期化に関する結論

Initialization is a more complex topic. 初期化は、より複雑なトピックです。 This is because we must not only consider whether class constructors execute, but we must also consider the evaluation of the initializer: というのも、これは、クラスのコンストラクタが実行されるか否かに関してだけでなく、その初期化子の評価についても考える必要があるためです。

int n = 5;    // Fine
int m = f();  // ? (Depends on f)
Foo x;        // ? (Depends on Foo::Foo)
Bar y = g();  // ? (Depends on g and on Bar::Bar)
int n = 5;    // OK
int m = f();  // ? (fに依存)
Foo x;        // ? (Fooのコンストラクタに依存)
Bar y = g();  // ? (gとBarのコンストラクタに依存)

All but the first statement expose us to indeterminate initialization ordering. 最初の例を除くすべての文において、潜在的に初期化順序の不確定性に関する問題を抱えている可能性があります。

The concept we are looking for is called constant initialization in the formal language of the C++ standard. この議論で見いだそうとしている概念は、C++標準の形式言語において「定数初期化」と呼ばれる概念にあたります。 It means that the initializing expression is a constant expression, and if the object is initialized by a constructor call, then the constructor must be specified as constexpr, too: 定数初期化とは、初期化式が定数式であるということを意味します。 また、定数となるオブジェクトがコンストラクタ呼び出しによって初期化される場合には、そのコンストラクタもconstexpr指定されていることも必要です。

struct Foo { constexpr Foo(int) {} };

int n = 5;  // Fine, 5 is a constant expression.
Foo x(2);   // Fine, 2 is a constant expression and the chosen constructor is constexpr.
Foo a[] = { Foo(1), Foo(2), Foo(3) };  // Fine
struct Foo { constexpr Foo(int) {} };

int n = 5;  // OK、 5 は定数式。
Foo x(2);   // OK、 2 は定数式で、選ばれるコンストラクタもconstexpr。
Foo a[] = { Foo(1), Foo(2), Foo(3) };  // OK

Constant initialization is always allowed. 定数初期化は、いつでも使ってかまいません。 Constant initialization of static storage duration variables should be marked with constexpr or constinit. 静的記憶域期間を持つ変数を定数初期化するときは、常にconstexprconstinitでマークします。 Any non-local static storage duration variable that is not so marked should be presumed to have dynamic initialization, and reviewed very carefully. そのようにマークされていない非ローカルな静的記憶域期間の変数は、動的初期化される可能性があるという前提のもと、非常に慎重なレビューを必要とします。

By contrast, the following initializations are problematic: これらの定数初期化とは対照的に、次の初期化には問題があります。

// Some declarations used below.
time_t time(time_t*);      // Not constexpr!
int f();                   // Not constexpr!
struct Bar { Bar() {} };

// Problematic initializations.
time_t m = time(nullptr);  // Initializing expression not a constant expression
Foo y(f());                // Ditto
Bar b;                     // Chosen constructor Bar::Bar() not constexpr
// 以降の初期化時に使用される式の宣言
time_t time(time_t*);      // constexprでない!
int f();                   // constexprでない!
struct Bar { Bar() {} };

// 問題のある初期化
time_t m = time(nullptr);  // 初期化式が定数式でない
Foo y(f());                // 同上
Bar b;                     // 選択されるコンストラクタ Bar::Bar() がconstexprでない

Dynamic initialization of nonlocal variables is discouraged, and in general it is forbidden. ローカル変数以外を動的初期化することは非推奨であり、原則としては禁止です。 However, we do permit it if no aspect of the program depends on the sequencing of this initialization with respect to all other initializations. ただし、その個々の初期化について、プログラムのあらゆる側面からみて、その初期化と他のすべての初期化との間に、順序付けに関する一切の依存性がないと見なせる場合は、そのような初期化を行ってもかまいません。 Under those restrictions, the ordering of the initialization does not make an observable difference. For example: そのような制限の下においては、初期化の順序の違いが、観測可能な違いとして現れることはありません。例を示します。

int p = getpid();  // Allowed, as long as no other static variable
                   // uses p in its own initialization.
int p = getpid();  // OK。ただし、他の静的変数の初期化において
                   // pを使用していないときに限る。

Dynamic initialization of static local variables is allowed (and common). 一方で、ローカル静的変数については、それらを動的に初期化してかまいません (むしろ、これらの変数は、動的初期化されることが一般的です)。

よくあるパターン

thread_local 変数

thread_local variables that aren't declared inside a function must be initialized with a true compile-time constant, and this must be enforced by using the ABSL_CONST_INIT attribute. thread_local変数が、関数スコープの外で宣言されるときは、真のコンパイル時定数で初期化されなくてはなりません。これはABSL_CONST_INIT属性を使用して強制されていなくてはなりません。 Prefer thread_local over other ways of defining thread-local data. また、スレッドごとにローカルなデータを定義したい場合は、他の方法よりも、thread_localを優先的に採用します。

Variables can be declared with the thread_local specifier: 変数は、次のように、thread_local指定子をつけて宣言することができます。

thread_local Foo foo = ...;

Such a variable is actually a collection of objects, so that when different threads access it, they are actually accessing different objects. このような変数は、実際にはオブジェクトのコレクションになり、アクセスするスレッドごとに異なるオブジェクトを参照することになります。 thread_local variables are much like static storage duration variables in many respects. thread_local変数は、多くの点で静的記憶域期間の変数によく似ています。 For instance, they can be declared at namespace scope, inside functions, or as static class members, but not as ordinary class members. たとえば、thread_local変数は、名前空間スコープ変数、関数内ローカル変数、または静的クラスメンバ変数として宣言できますが、通常のクラスメンバ変数として宣言することはできません。

thread_local variable instances are initialized much like static variables, except that they must be initialized separately for each thread, rather than once at program startup. thread_local変数のインスタンスは、「プログラムの起動時に一度だけ」ではなく「スレッドごとに個別に」初期化されるという点を除けば、ほとんど静的変数と同じように初期化されます。 This means that thread_local variables declared within a function are safe, but other thread_local variables are subject to the same initialization-order issues as static variables (and more besides). これは、関数内で宣言されるthread_local変数は安全であり、それ以外の場所で宣言されるthread_local変数は、静的変数と同様に、初期化順序やその他の問題の影響を受けることを意味します。

thread_local variabls have a subtle destruction-order issue: during thread shutdown, thread_local variables will be destroyed in the opposite order of their initialization (as is generally true in C++). thread_local変数には、破壊順序に関する微妙な問題もあります。thread_local変数は、スレッドが終了するときに破壊されますが、それらの破壊順序は、 (C++が全般的にそうであるように、) それらの初期化順の逆順となります。 If code triggered by the destructor of any thread_local variable refers to any already-destroyed thread_local on that thread, we will get a particularly hard to diagnose use-after-free. あるthread_local変数のデストラクタから呼び出されるコードが、同スレッドで既に破壊済みの別のthread_local変数を参照していると、特に診断の難しい use-after-free バグ(デストラクタ実行後やメモリ解放後の変数にアクセスしてしまうバグ)を引き起こしてしまうかもしれません。

thread_local variables at class or namespace scope must be initialized with a true compile-time constant (i.e., they must have no dynamic initialization). クラススコープや名前空間スコープのthread_local変数は、真のコンパイル時定数で初期化されなければなりません。(すなわち、動的初期化されてはなりません。) To enforce this, thread_local variables at class or namespace scope must be annotated with ABSL_CONST_INIT (or constexpr, but that should be rare): これを強制するため、そのようなスコープのthread_local変数は ABSL_CONST_INITでマークされていなければなりません (もしくはconstexprでマークしてもかまいませんが、こちらをthread_localで使うのはレアケースでしょう)。

thread_local variables inside a function have no initialization concerns, but still risk use-after-free during thread exit. thread_local変数を関数内スコープで宣言する場合は、初期化時の懸念事項はなくなります。ただし、依然としてスレッド終了時のuse-after-freeバグに関する危険性は残ります。 Note that you can use a function-scope thread_local to simulate a class- or namespace-scope thread_local by defining a function or static method that exposes it: なお、次のように、関数や静的数内スコープのthread_localを定義することによって、クラススコープや名前空間スコープのthread_local変数の代替手段として用いることができます。テクニックとして覚えておくとよいでしょう。

Foo& MyThreadLocalFoo() {
    thread_local Foo result = ComplicatedInitialization();
    return result;
}

Note that thread_local variables will be destroyed whenever a thread exits. thread_local変数が破壊されるのはスレッド終了時です。 If the destructor of any such variable refers to any other (potentially-destroyed) thread_local we will suffer from hard to diagnose use-after-free bugs. もし、これらの変数のデストラクタで、他の (潜在的に破壊済みかもしれない) thread_local変数を参照していると、診断が困難なuse-after-freeバグに悩まされるかもしれません。 Prefer trivial types, or types that provably run no user-provided code at destruction to minimize the potential of accessing any other thread_local. このような潜在的に問題のあるアクセスをなるべく避けるために、thread_local変数には、自明(trivial)な型や、ユーザー定義デストラクタを持たない型を用いる方が望ましいでしょう。

thread_local should be preferred over other mechanisms for defining thread-local data. また、スレッドローカルなデータを定義するときは、他の仕組みよりも、thread_localを優先的に採用しましょう。

クラス

Classes are the fundamental unit of code in C++. クラスはC++におけるコードの基本単位です。 Naturally, we use them extensively. もちろん、私たちは、すでにクラスを広く使っています。 This section lists the main dos and don'ts you should follow when writing a class. このセクションでは、クラスを書くときに、すべきこと、すべきでないことについて説明します。

コンストラクタで行うこと

Avoid virtual method calls in constructors, and avoid initialization that can fail if you can't signal an error. コンストラクタで仮想メンバ関数を呼んではいけません。 また、エラーを伝える何らかの手段がない場合、失敗する可能性のある初期化処理を行ってはいけません。

It is possible to perform arbitrary initialization in the body of the constructor. コンストラクタでは任意の初期化処理を行うことができます。

Constructors should never call virtual functions. コンストラクタでは仮想関数を呼び出してはいけません。 If appropriate for your code , terminating the program may be an appropriate error handling response. コンストラクタで発生するエラーの処理の方法としては、適切な場合には、そのままプログラムを強制終了するのも1つの手段でしょう。 Otherwise, consider a factory function or Init() method as described in TotW #42 . さもなくば、TotW #42で説明されているような、ファクトリ関数やInit()メソッドの導入を検討しましょう。 Avoid Init() methods on objects With no other states that affect which public methods may be called (semi-constructed objects of this form are particularly hard to work with correctly). どのパブリックメソッドを呼びだせるかに影響するような他の状態を持たないオブジェクトではInit()メソッドは避けてください(この形の中途半端に構築されたオブジェクトを正しく扱うのは非常に困難です)。

暗黙的型変換

Do not define implicit conversions. 暗黙的型変換を定義してはいけません。 Use the explicit keyword for conversion operators and single-argument constructors. 型変換演算子や、引数1つのコンストラクタには、explicitキーワードを使用してください。

Implicit conversions allow an object of one type (called the source type) to be used where a different type (called the destination type) is expected, such as when passing an int argument to a function that takes a double parameter. 暗黙的型変換によって、ある型(変換元の型)のオブジェクトを、異なる型(変換先の型)が期待される箇所で用いることができるようになります。たとえば、double型の引数をとる関数にint型の値を渡すといった例が考えられます。

In addition to the implicit conversions defined by the language, users can define their own, by adding appropriate members to the class definition of the source or destination type. 言語で元々定義されている暗黙的型変換に加えて、変換元の型か変換先の型のクラス定義に適切なメンバを加えることで、独自の暗黙的型変換を定義することができます。 An implicit conversion in the source type is defined by a type conversion operator named after the destination type (e.g., operator bool()). 変換元の型で暗黙的型変換を定義するには、変換先の型の名前をもつ型変換演算子を定義します(例:operator bool())。 An implicit conversion in the destination type is defined by a constructor that can take the source type as its only argument (or only argument with no default value). 変換先の型で暗黙的型変換を定義するには、変換元の型の引数を1つだけとる(またはデフォルト値のない引数を1つだけとる)コンストラクタを定義します。

The explicit keyword can be applied to a constructor or a conversion operator, to ensure that it can only be used when the destination type is explicit at the point of use, e.g., with a cast. explicitキーワードは、コンストラクタや型変換演算子に適用することができ、キャストなどによって変換先の型が明示された場合にのみ変換が行われるように限定することができます。 This applies not only to implicit conversions, but to list initialization syntax: これは、暗黙的型変換を防ぐだけではなく、以下に示すようなリスト初期化構文にも適用されます。

class Foo {
  explicit Foo(int x, double y);
  ...
};

void Func(Foo f);
Func({42, 3.14});  // Error
This kind of code isn't technically an implicit conversion, but the language treats it as one as far as explicit is concerned. これに類するコードは、技術的には暗黙的型変換ではありませんが、言語系からは暗黙的変換の一種のように扱われ、explicitの影響を受けることになります。

Type conversion operators, and constructors that are callable with a single argument, must be marked explicit in the class definition. 型変換演算子、および、引数1つで呼び出せるコンストラクタは、クラス定義においてexplicitでマークされていなくてはなりません。 As an exception, copy and move constructors should not be explicit, since they do not perform type conversion. 例外として、コピーコンストラクタとムーブコンストラクタについては、explicitでマークしてはいけません (これらのコンストラクタは型変換は行いません)。 Implicit conversions can sometimes be necessary and appropriate for types that are designed to be interchangeable, for example when objects of two types are just different representations of the same underlying value. 場合によっては、暗黙的型変換が必要かつ適切であることもあります。たとえば、ある2つの型が、同じ意味の値に対して表現方法のみが異なるようなときは、型を相互に交換可能であるように設計してもよいでしょう。 ((訳注: std::chrono::durationなどでしょうか)) In that case, contact your project leads to request a waiver of this rule. この場合は、プロジェクトリーダーと相談し、このルールの適用外としてください。

Constructors that cannot be called with a single argument may omit explicit. 引数1つで呼び出せないコンストラクタについては、explicitを省略してかまいません。 Constructors that take a single std::initializer_list parameter should also omit explicit, in order to support copy-initialization (e.g., MyType m = {1, 2};). また、引数にstd::initializer_listを1つだけとるコンストラクタについても、コピーによる初期化(MyType m = {1, 2};の形)をサポートするためにexplicitを省略してください。

コピー可能な型・ムーブ可能な型

A class's public API must make clear whether the class is copyable, move-only, or neither copyable nor movable. クラスを定義するときは、その公開APIにおいて、その型のオブジェクトがコピー可能なのか、ムーブのみ可能なのか、あるいは、いずれも不可能なのか明確にわかるようにしておかなければなりません。 Support copying and/or moving if these operations are clear and meaningful for your type. オブジェクトのコピー操作やムーブ操作について明確かつ意味が通るのであれば、型でそれらの操作を提供してください。

A movable type is one that can be initialized and assigned from temporaries. 「型がムーブ可能である」とは、一時オブジェクトから新たなオブジェクトを初期化可能および代入可能であることを言います。

A copyable type is one that can be initialized or assigned from any other object of the same type (so is also movable by definition), with the stipulation that the value of the source does not change. 「型がコピー可能である」とは、同じ型の別のオブジェクトから、そのオブジェクトの値を変化させることなく、新たなオブジェクトを初期化可能および代入可能であることを言います。(その定義から、コピー可能な型は、同時にムーブ可能でもあります。) std::unique_ptr<int> is an example of a movable but not copyable type (since the value of the source std::unique_ptr<int> must be modified during assignment to the destination). たとえば、std::unique_ptr<int>は、ムーブ可能であるがコピーは不可な型の一例です。(別のstd::unique_ptr<int>変数への代入操作を行うときには、代入操作に使われる元の値が変更される必要があります。) int and std::string are examples of movable types that are also copyable. intstd::stringは、ムーブもコピーも可能な型の例です。 (For int, the move and copy operations are the same; for std::string, there exists a move operation that is less expensive than a copy.) (intにおいてはムーブ操作とコピー操作が同一となり、 std::stringにおいては、コピー操作よりも低コストなムーブ操作が提供されています。) For user-defined types, the copy behavior is defined by the copy constructor and the copy-assignment operator. ユーザー定義の型において、コピーの挙動はコピーコンストラクタとコピー代入演算子によって定義されます。 Move behavior is defined by the move constructor and the move-assignment operator, if they exist, or by the copy constructor and the copy-assignment operator otherwise. ムーブの挙動は、ムーブコンストラクタとムーブ代入演算子が定義されていれば、それらによって定義され、定義されていなければコピー操作と同一になります。

The copy/move constructors can be implicitly invoked by the compiler in some situations, e.g., when passing objects by value. コピーコンストラクタやムーブコンストラクタは、オブジェクトを値渡しするときなどに、コンパイラによって暗黙的に呼び出されます。

Objects of copyable and movable types can be passed and returned by value, which makes APIs simpler, safer, and more general. コピー可能な型・ムーブ可能な型のオブジェクトは値渡し・値戻しすることができます。これによって、よりシンプルで、より安全で、より一般的な形のAPIを定義することができるようになります。 Unlike when passing objects by pointer or reference, there's no risk of confusion over ownership, lifetime, mutability, and similar issues, and no need to specify them in the contract. 値渡しは、ポインタ渡し・参照渡しと異なり、オブジェクトの所有権や寿命、変更可能性、その他のそれに類する危険がなく、APIにおいてそれらに関する前提条件を定める必要がなくなります。 It also prevents non-local interactions between the client and the implementation, which makes them easier to understand, maintain, and optimize by the compiler. また、呼び出し元と実装をつないでしまうような非局所的な相互作用も自動的に防がれるため、オブジェクトを理解しやすくメンテナンスしやすい形で実装することができ、同時に、コンパイラによる最適化も掛かりやすくなります。 Further, such objects can be used with generic APIs that require pass-by-value, such as most containers, and they allow for additional flexibility in e.g., type composition. さらに、このようなオブジェクトは、多くのコンテナ型のように値渡しを要求する一般的なAPIにも用いることができますし、あるいは、型の抱合(composition)などを行う際にも、より柔軟に対応することができるでしょう。

Copy/move constructors and assignment operators are usually easier to define correctly than alternatives like Clone(), CopyFrom() or Swap(), because they can be generated by the compiler, either implicitly or with = default. コピーコンストラクタ、ムーブコンストラクタ、また関連する代入演算子は、暗黙的に、あるいは明示的に= defaultと記述することで、その実装をコンパイラに生成させることができます。このため、Clone(), CopyFrom(), Swap()のような代替手段を実装するのに比べて、比較的、正しい実装を得ることが容易です。 They are concise, and ensure that all data members are copied. 自動生成されるコンストラクタや代入演算子は簡潔で、しかも、すべてのメンバがコピーされることが保証されます。 Copy and move constructors are also generally more efficient, because they don't require heap allocation or separate initialization and assignment steps, and they're eligible for optimizations such as copy elision. また、一般に、これらの代替手段よりも、コピーコンストラクタやムーブコンストラクタを用いる方が効率的にもなりやすいです。これらのコンストラクタを用いる場合は、ヒープメモリの確保が不要になり、初期化と割り当てをまとめて行えて、かつ、コピーの省略のような最適化に対しても適格となるためです。

Move operations allow the implicit and efficient transfer of resources out of rvalue objects. ムーブ操作によって、右辺値オブジェクトから暗黙的かつ効率的にリソースを取り出すことが可能になります。 This allows a plainer coding style in some cases. また、場合によっては、より簡潔なコーディングスタイルを採用できるようにもなるでしょう。

Some types do not need to be copyable, and providing copy operations for such types can be confusing, nonsensical, or outright incorrect. 型によっては、コピー操作が不要であったり、そもそもコピー操作を提供すること自体が、概念上おかしい場合があります。 Types representing singleton objects (Registerer), objects tied to a specific scope (Cleanup), or closely coupled to object identity (Mutex) cannot be copied meaningfully. たとえば、(Registererのような)シングルトンオブジェクトや、(Cleanupのような)そのスコープに紐付くオブジェクト、あるいは(Mutexのような)その識別子自体と紐付けて使われるオブジェクトは、意味のある形でコピーを定義できません。

Copy operations for base class types that are to be used polymorphically are hazardous, because use of them can lead to object slicing. ポリモーフィズムを使用しているような型においては、基底クラスに対するコピー操作は、オブジェクトのスライシングを引き起こす可能性があるため、非常に危険です。 Defaulted or carelessly-implemented copy operations can be incorrect, and the resulting bugs can be confusing and difficult to diagnose. コピー操作をデフォルトのままにしていたり、深く考えずにコピー操作を定義してしまうと、それらの実装は正しくない実装になる可能性があり、その結果として診断の難しい困惑的なバグを招くかもしれません。

Copy constructors are invoked implicitly, which makes the invocation easy to miss. また、コピーコンストラクタは暗黙的に呼び出されるため、その呼び出しそのものも見落としやすいです。 This may cause confusion for programmers used to languages where pass-by-reference is conventional or mandatory. これは、参照渡しが慣習的(あるいは必須)であるような他のプログラミング言語に慣れ親しんでいるプログラマーにとっては、特に困惑的なポイントかもしれません。 It may also encourage excessive copying, which can cause performance problems. また、これによって、オブジェクトの過度なコピーが助長され、パフォーマンス上の問題となって表れるかもしれません。

Every class's public interface must make clear which copy and move operations the class supports. すべてのクラスの公開インターフェースにおいて、その型がサポートするコピー・ムーブ操作について明確にしてください。 This should usually take the form of explicitly declaring and/or deleting the appropriate operations in the public section of the declaration. これは、通常は、クラス定義のpublicセクションにおいて、対応する操作を明示的に宣言あるいは削除することによって行います。

Specifically, a copyable class should explicitly declare the copy operations, a move-only class should explicitly declare the move operations, and a non-copyable/movable class should explicitly delete the copy operations. すなわち、コピー可能なクラスではコピー操作を明示的に宣言し、ムーブのみ可能なクラスではムーブ操作を明示的に宣言し、コピーもムーブもできないクラスでは、コピー操作を明示的に削除しましょう。 A copyable class may also declare move operations in order to support efficient moves. コピー可能クラスにおいては、より効率的なムーブを提供するために、追加のムーブ操作を宣言をしてもかまいません。 Explicitly declaring or deleting all four copy/move operations is permitted, but not required. 4つのコピー・ムーブ操作すべてを明示的に宣言または削除してもかまいませんが、必須ではありません。 If you provide a copy or move assignment operator, you must also provide the corresponding constructor. ただし、コピー代入演算子やムーブ代入演算子を提供する場合は、必ずその操作に対応するコンストラクタも提供するようにしてください。

class Copyable {
 public:
  Copyable(const Copyable& other) = default;
  Copyable& operator=(const Copyable& other) = default;

  // The implicit move operations are suppressed by the declarations above.
  // You may explicitly declare move operations to support efficient moves.
};

class MoveOnly {
 public:
  MoveOnly(MoveOnly&& other) = default;
  MoveOnly& operator=(MoveOnly&& other) = default;

  // The copy operations are implicitly deleted, but you can
  // spell that out explicitly if you want:
  MoveOnly(const MoveOnly&) = delete;
  MoveOnly& operator=(const MoveOnly&) = delete;
};

class NotCopyableOrMovable {
 public:
  // Not copyable or movable
  NotCopyableOrMovable(const NotCopyableOrMovable&) = delete;
  NotCopyableOrMovable& operator=(const NotCopyableOrMovable&)
      = delete;

  // The move operations are implicitly disabled, but you can
  // spell that out explicitly if you want:
  NotCopyableOrMovable(NotCopyableOrMovable&&) = delete;
  NotCopyableOrMovable& operator=(NotCopyableOrMovable&&)
      = delete;
};
class Copyable {
 public:
  Copyable(const Copyable& other) = default;
  Copyable& operator=(const Copyable& other) = default;

  // 暗黙的ムーブ操作は、上記の宣言によって抑制されます。
  // 効率的なムーブをサポートするために、明示的にムーブ操作を宣言してもかまいません。
};

class MoveOnly {
 public:
  MoveOnly(MoveOnly&& other) = default;
  MoveOnly& operator=(MoveOnly&& other) = default;

  // コピー操作は暗黙的に削除されます。
  // 次のように、明示的に宣言してもかまいません。
  MoveOnly(const MoveOnly&) = delete;
  MoveOnly& operator=(const MoveOnly&) = delete;
};

class NotCopyableOrMovable {
 public:
  // コピーもムーブも不可
  NotCopyableOrMovable(const NotCopyableOrMovable&) = delete;
  NotCopyableOrMovable& operator=(const NotCopyableOrMovable&)
      = delete;

  // この例では、ムーブ操作は暗黙的に無効になります。
  // 次のように、明示的に宣言してもかまいません。
  NotCopyableOrMovable(NotCopyableOrMovable&&) = delete;
  NotCopyableOrMovable& operator=(NotCopyableOrMovable&&)
      = delete;
};

These declarations/deletions can be omitted only if they are obvious: これらの宣言や削除宣言は、型がどの操作をサポートするか明確であるときに限り、省略してもかまいません。

A type should not be copyable/movable if the meaning of copying/moving is unclear to a casual user, or if it incurs unexpected costs. カジュアルなユーザーから見て、ある型のコピー・ムーブ操作の意味が不明瞭であるとき、あるいは、それらの操作によって予期しないコストが発生するときは、その型をコピー可能あるいはムーブ可能にしないでください。 Move operations for copyable types are strictly a performance optimization and are a potential source of bugs and complexity, so avoid defining them unless they are significantly more efficient than the corresponding copy operations. コピー可能な型における追加のムーブ操作は、厳密に考えるとパフォーマンス上の最適化にあたり、潜在的にバグや複雑さの要因となります。よって、このような型の追加のムーブ操作は、そのコピー操作よりもはるかに効率的に実現できるような場合に限って定義するものとし、それ以外の場合には実装しないでください。 If your type provides copy operations, it is recommended that you design your class so that the default implementation of those operations is correct. 新しい型でコピー操作を提供する場合は、できるだけ、コンパイラが生成するデフォルト実装がそのまま正しい実装となるように型を設計してください。 Remember to review the correctness of any defaulted operations as you would any other code. また、コピー・ムーブ操作について、コンパイラ生成のデフォルト実装に任せる場合であっても、それらのデフォルト実装によって正しくコピーあるいはムーブの操作が実現できているのかどうか、他のコードと同じようにレビューするようにしてください。

To eliminate the risk of slicing, prefer to make base classes abstract, by making their constructors protected, by declaring their destructors protected, or by giving them one or more pure virtual member functions. オブジェクトスライシングのリスクを排除するため、継承における基底クラスは抽象クラスとする方が望ましいです。クラスを抽象クラスにするためには、コンストラクタをprotectedにするか、デストラクタをprotectedにするか、あるいは、1つ以上の純粋仮想メンバ関数を宣言します。 Prefer to avoid deriving from concrete classes. また、具象クラスからさらなる派生クラスを作ることは避ける方が望ましいです。

構造体(struct)か、クラス(class)か

Use a struct only for passive objects that carry data; everything else is a class. structはデータを運ぶための受動的なオブジェクトにのみ使用します。それ以外のすべての用途でclassを使用します。

The struct and class keywords behave almost identically in C++. C++において、structclassはほとんど同じ振る舞いをします。 We add our own semantic meanings to each keyword, so you should use the appropriate keyword for the data-type you're defining. 私たちは、それぞれのキーワードに独自の意味づけをしており、定義するデータの種類に応じて適切なキーワードを使い分けています。

structs should be used for passive objects that carry data, and may have associated constants. structはデータを運ぶための受動的なオブジェクトに使用します。関連する定数を含んでもかまいません。 All fields must be public. すべてのフィールドはpublicでなければなりません。 The struct must not have invariants that imply relationships between different fields, since direct user access to those fields may break those invariants. 異なるフィールド間にまたがる暗黙的な不変条件を持ってはいけません。 これらのフィールドは、ユーザーによって直接アクセスされるため、そのような不変条件はそもそも維持することができません。 Constructors, destructors, and helper methods may be present; however, these methods must not require or enforce any invariants. コンストラクタやデストラクタ、その他のヘルパーメソッドを定義してもかまいません。 しかし、それらのメソッドにおいても、何らかの不変条件を要求したり強制したりしてはいけません。

If more functionality or invariants are required, or struct has wide visibility and expected to evolve, then a class is more appropriate. それ以上の機能性や不変条件を必要とする場合、あるいは、その構造体が広い範囲から可視であり、今後の拡張が予見される場合には、classを使う方が適切です。 If in doubt, make it a class. 迷ったときはclassにしてください。

For consistency with STL, you can use struct instead of class for stateless types, such as traits, template metafunctions, and some functors. 型トレイトやテンプレートメタ関数、関数オブジェクトなどに代表されるような、状態を何も持たない型については、STLとの一貫性を保つ目的でclassのかわりにstructを使ってもかまいません。

Note that member variables in structs and classes have different naming rules. なお、structclassでは、メンバ変数の命名規則が異なりますので注意してください。

構造体(struct)か、ペア(pair)・タプル(tupple)か

Prefer to use a struct instead of a pair or a tuple whenever the elements can have meaningful names. その要素に意味のある名前を付けられるならば、pairtupleで済ませることなく、常にstructを定義して使います。

While using pairs and tuples can avoid the need to define a custom type, potentially saving work when writing code, a meaningful field name will almost always be much clearer when reading code than .first, .second, or std::get<X>. ペアやタプルを用いると、型を独自に定義する手間を省けるため、コードを書くときに、いくらか楽をすることができるかもしれません。しかし、コードを読むときのことを考えれば、.first.secondstd::get<0>()などよりも、意味のあるフィールド名を用いる方が、ほとんど常に、はるかにわかりやすいはずです。 While C++14's introduction of std::get<Type> to access a tuple element by type rather than index (when the type is unique) can sometimes partially mitigate this, a field name is usually substantially clearer and more informative than a type. タプルの中で型が一意なときは、C++14からのstd::get<Type>()を用いることで、インデックスではなく型名で要素にアクセスできるため、この状況はいくらか改善するかもしれません。しかし、いずれにせよ、通常は型名よりもフィールド名の方が明確であり、含まれる情報量も多いでしょう。

Pairs and tuples may be appropriate in generic code where there are not specific meanings for the elements of the pair or tuple. ペアやタプルは、その各要素に特定の意味を定められないような、汎用的なコードにおいては適切な場合もあります。 Their use may also be required in order to interoperate with existing code or APIs. あるいは、既存のコードやAPIとの相互運用のためにペアやタプルを必要とすることもあるでしょう。

継承

Composition is often more appropriate than inheritance. 継承よりも抱合(composition)を用いる方がより適切な場合も多いです。 When using inheritance, make it public. 継承を用いるときは、必ずpublicにします。

When a sub-class inherits from a base class, it includes the definitions of all the data and operations that the base class defines. あるクラスが何らかの基底クラスを継承するとき、その派生クラスには基底クラスが定義するすべてのデータと操作が含まれます。 "Interface inheritance" is inheritance from a pure abstract base class (one with no state or defined methods); all other inheritance is "implementation inheritance". 「インターフェースの継承」は、純粋抽象基底クラス(状態やメソッドの定義を一切持たないクラス)からの継承のことを言い、それ以外の継承はすべて「実装の継承」です。

Implementation inheritance reduces code size by re-using the base class code as it specializes an existing type. 実装の継承は、既存の型を特殊化する際に基底クラスのコードを再利用するため、コードのサイズが小さくなります。 Because inheritance is a compile-time declaration, you and the compiler can understand the operation and detect errors. 継承はコンパイル時の宣言であるため、プログラマーとコンパイラとの両者によってその操作が理解され、エラーがあれば検出することができます。 Interface inheritance can be used to programmatically enforce that a class expose a particular API. インターフェースの継承を用いると、派生クラスに対して所定のAPIを公開することをプログラム的に強制できます。 Again, the compiler can detect errors, in this case, when a class does not define a necessary method of the API. APIに要求されるメソッドが派生クラスにおいて定義されていないとき、やはり、コンパイラはそれをエラーとして検出することができます。

For implementation inheritance, because the code implementing a sub-class is spread between the base and the sub-class, it can be more difficult to understand an implementation. 実装の継承を行うと、派生クラスの実装コードが物理的に基底クラスと派生クラスとの間に分散してしまうため、実装を理解するのがより難しくなるかもしれません。 The sub-class cannot override functions that are not virtual, so the sub-class cannot change implementation. また、派生クラスでは、基底クラスでvirtual宣言されていない関数をオーバーライドできないため、派生クラスでそれらの実装を変えることはできません。

Multiple inheritance is especially problematic, because it often imposes a higher performance overhead (in fact, the performance drop from single inheritance to multiple inheritance can often be greater than the performance drop from ordinary to virtual dispatch), and because it risks leading to "diamond" inheritance patterns, which are prone to ambiguity, confusion, and outright bugs. 多重継承は特に問題を引き起こしやすいです。 多重継承を行うとパフォーマンス上のオーバーヘッドが大きくなります (実際、単一継承から多重継承に変更する際に生ずるパフォーマンス低下は、通常の関数呼び出しを仮想呼び出しに変更する際のものと比べても大きくなりがちです)。 また、曖昧で困惑的であからさまなバグを引き起こしがちな、「ダイヤモンド継承」パターンに繋がってしまうリスクもあります。

All inheritance should be public. すべての継承はpublicで行います。 If you want to do private inheritance, you should be including an instance of the base class as a member instead. privateな継承を行いたいときは、継承のかわりに、基底クラスのインスタンスをメンバとして持つようにしてください。 You may use final on classes when you don't intend to support using them as base classes. 基底クラスとして使用されることを想定しないクラスにはfinalをつけてもかまいません。

Do not overuse implementation inheritance. 実装の継承を濫用しないでください。 Composition is often more appropriate. 多くの場合において抱合(composition)の方がより適切です。 Try to restrict use of inheritance to the "is-a" case: Bar subclasses Foo if it can reasonably be said that Bar "is a kind of" Foo. 継承は「is-a」関係が成立する場合に限って使用するようにしてください。 たとえばFooを継承してBarを作ってよいのは、理屈の上で「BarFooの一種」と言えるときだけです。

Limit the use of protected to those member functions that might need to be accessed from subclasses. protectedセクションを用いるのは、派生クラスからのアクセスが必要なメンバ関数だけにとどめてください。 Note that data members should be private . なお、データメンバはすべてprivateとしてください

Explicitly annotate overrides of virtual functions or virtual destructors with exactly one of an override or (less frequently) final specifier. 仮想関数や仮想デストラクタをオーバーライドするときは、override指定子か(それほど頻繁ではありませんが)final指定子のいずれか1つをつけて、オーバーライドしていることを明示してください。 Do not use virtual when declaring an override. オーバーライドを明示する目的でvirtualを使ってはいけません。 Rationale: A function or destructor marked override or final that is not an override of a base class virtual function will not compile, and this helps catch common errors. この理由としては、仮想関数や仮想デストラクタをオーバーライドするとき、その意図をoverridefinalで表しておくことで、それらの宣言が基底クラスの関数をオーバーライドしなかったときにコンパイルエラーとなり、間違いに気づくことができるようになるからです。 The specifiers serve as documentation; if no specifier is present, the reader has to check all ancestors of the class in question to determine if the function or destructor is virtual or not. そして、これらの指定子はドキュメントの役割も果たします。これらの指定子が書かれていないものがあると、コードの読者は、それぞれの関数やデストラクタが仮想なのか否かを把握するために、すべての継承元をたどって調べなければならなくなってしまいます。

Multiple inheritance is permitted, but multiple implementation inheritance is strongly discouraged. 多重継承は禁止しませんが、実装の多重継承は、強く非推奨とします。

演算子のオーバーロード

Overload operators judiciously. 演算子のオーバーロードは慎重に。 Do not use user-defined literals. ユーザー定義リテラルは使ってはいけません。

C++ permits user code to declare overloaded versions of the built-in operators using the operator keyword, so long as one of the parameters is a user-defined type. C++では、operatorキーワードを使うことで、ユーザー定義の型を引数とした組み込み演算子のオーバーロードを宣言することができます。 The operator keyword also permits user code to define new kinds of literals using operator"", and to define type-conversion functions such as operator bool(). また、operator""を用いることで新しいリテラルを定義することもできます。この他、operator bool()のような、型変換を行う関数を定義することもできます。

Operator overloading can make code more concise and intuitive by enabling user-defined types to behave the same as built-in types. 演算子のオーバーロードを用いると、ユーザー定義型を組み込み型と同様に振る舞わせることができるようになり、コードがより簡潔で直感的になります。 Overloaded operators are the idiomatic names for certain operations (e.g., ==, <, =, and <<), and adhering to those conventions can make user-defined types more readable and enable them to interoperate with libraries that expect those names. オーバーロードされた演算子は、所定の操作に対する慣例的な見た目(==, <, =, <<など)をしており、これらの慣例に従うことによって、ユーザー定義の型に対する可読性を向上させ、また、このような演算子の存在を前提とするライブラリとの相互運用性も高めることができます。

User-defined literals are a very concise notation for creating objects of user-defined types. また、ユーザー定義リテラルは、ユーザー定義のオブジェクトを生成するための非常に簡潔な表記方法を提供します。

Define overloaded operators only if their meaning is obvious, unsurprising, and consistent with the corresponding built-in operators. 演算子のオーバーロードは、コード読者から見て、その意味が明らかであり、動作を予測可能であり、かつ、組み込み演算子との一貫性が保てるときに限り定義してください。 For example, use | as a bitwise- or logical-or, not as a shell-style pipe. たとえば、|演算子は、ビット和か論理和の意味でのみ使い、シェルのパイプのような意味では使ってはいけません。

Define operators only on your own types. 演算子は、自分で定義した型に対するもののみを定義してください。 More precisely, define them in the same headers, .cc files, and namespaces as the types they operate on. より正確には、ある型に対する演算子は、その型の定義と同じヘッダーファイルか.ccファイルの中で、その型と同じ名前空間の中で定義してください。 That way, the operators are available wherever the type is, minimizing the risk of multiple definitions. そのようにしておけば、型が利用可能なところでは常に演算子も利用可能となり、同一の演算子が多重定義されるリスクを最小限にとどめることができます。 If possible, avoid defining operators as templates, because they must satisfy this rule for any possible template arguments. できれば、演算子をテンプレートとして定義するのは避けてください。 テンプレートとして宣言された演算子は、取り得る限りすべてのテンプレート引数において、これらのルールを満たしていなければなりません。 If you define an operator, also define any related operators that make sense, and make sure they are defined consistently. ある演算子を定義する場合には、それに関連する演算子も正しく定義し、必ず一貫性を保つようにしてください。 For example, if you overload <, overload all the comparison operators, and make sure < and > never return true for the same arguments. たとえば、<をオーバーロードしたならば、その他のすべての比較演算子もオーバーロードしてください。 そして、ある引数の組に対する比較演算<>の結果が両方とも真となるようなことがないようにしてください。

Prefer to define non-modifying binary operators as non-member functions. 引数に対して変更を伴わない二項演算子は、非メンバ関数として定義される方が望ましいです。 If a binary operator is defined as a class member, implicit conversions will apply to the right-hand argument, but not the left-hand one. 二項演算子がクラスのメンバとして定義されていると、演算子の右辺については暗黙的型変換が適用されますが、左辺には適用されなくなってしまいます。 It will confuse your users if a + b compiles but b + a doesn't. a + bがコンパイルできてb + aがコンパイルエラーになるような状況は、ユーザーの困惑を招きます。

For a type T whose values can be compared for equality, define a non-member operator== and document when two values of type T are considered equal. ある型Tがその値の等値性を比較できるとき、非メンバのoperator==を定義した上で、どういう場合にそれらが等値と見なされるのかについてドキュメント化してください。 If there is a single obvious notion of when a value t1 of type T is less than another such value t2 then you may also define operator<=>, which should be consistent with operator==. また、型Tの値t1と別の値t2を大小比較するための、唯一で、かつ明らかな概念が存在するならば、operator<=>を定義してもかまいません。 その際、operator==との一貫性を保ってください。 Prefer not to overload the other comparison and ordering operators. また、これ以外の比較演算子はオーバーロードしない方がよよいでしょう。

Don't go out of your way to avoid defining operator overloads. 演算子のオーバーロードをわざわざ避けるようなことはしないでください。 For example, prefer to define ==, =, and <<, rather than Equals(), CopyFrom(), and PrintTo(). Equals()CopyFrom()PrintTo()などを用意するよりも、===<<を定義する方が望ましいです。 Conversely, don't define operator overloads just because other libraries expect them. 反対に、他のライブラリの要件に合わせる目的のためだけに演算子をオーバーロードすることは避けてください。 For example, if your type doesn't have a natural ordering, but you want to store it in a std::set, use a custom comparator rather than overloading <. たとえば、値の大小比較関係を自然に定義できない型のオブジェクトをstd::setに入れたいときであっても、この目的で比較演算子<をオーバーロードしてはいけません。このような場合には、独自の比較子(comparator)を使うようにしてください。

Do not overload &&, ||, , (comma), or unary &. 演算子&&||, (カンマ演算子)、単項演算子&はオーバーロードをしてはいけません。 Do not overload operator"", i.e., do not introduce user-defined literals. また、operator""もオーバーロードしてはいけません。すなわち、ユーザー定義リテラルを導入してはなりません。 Do not use any such literals provided by others (including the standard library). そして、標準ライブラリも含めて、他者から提供されるいかなるリテラル演算子も使用してはなりません。

Type conversion operators are covered in the section on implicit conversions. 型変換演算子については暗黙的型変換のセクションでカバーします。 The = operator is covered in the section on copy constructors. 代入演算子=コピーコンストラクタのセクションでカバーします。 Overloading << for use with streams is covered in the section on streams. ストリーム用途での演算子<<のオーバーロードについては、ストリームのセクションでカバーします。 See also the rules on function overloading, which apply to operator overloading as well. また、これらを含む、すべての演算子のオーバーロードにおいて、関数のオーバーロードにあるルールも同様に適用されますので、あわせて参照してください。

アクセス制限

Make classes' data members private, unless they are constants. クラスのデータメンバは、定数を除いて、すべてprivateにします。 This simplifies reasoning about invariants, at the cost of some easy boilerplate in the form of accessors (usually const) if necessary. このルールは、定型文的なgetter関数(通常はconst)の実装を強制しますが、それを差し引いても、クラスの不変条件に関する議論をシンプルにできるメリットがあります。

For technical reasons, we allow data members of a test fixture class defined in a .cc file to be protected when using Google Test . Google Testを使う場合、技術的な理由により、テストフィクスチャクラスが.ccファイル内で定義される場合に限り、そのデータメンバをprotectedにしてもよいとします。 If a test fixture class is defined outside of the .cc file it is used in, for example in a .h file, make data members private. それ以外の場所(たとえば.hファイル内)でテストフィクスチャクラスが定義される場合は、データメンバはprivateにしなければなりません。

宣言の順序

Group similar declarations together, placing public parts earlier. 似ている宣言をグループにまとめます。public部分を先頭に置きます。

A class definition should usually start with a public: section, followed by protected:, then private:. クラスの定義は、通常はpublic:セクションから始め、protected:private:と続けます。 Omit sections that would be empty. 中身のないセクションは省略してください。

Within each section, prefer grouping similar kinds of declarations together, and prefer the following order: 各セクションにおいて、似た種類の宣言をまとめるようにし、以下の順に並べるようにします。

  1. Types and type aliases (typedef, using, enum, nested structs and classes, and friend types) 型と型エイリアス(typedef, using, enum, ネストされた構造体やクラス, friend型)
  2. (Optionally, for structs only) non-static data members (構造体に限り、必要に応じて)非staticデータメンバ
  3. Static constants 静的定数
  4. Factory functions ファクトリ関数
  5. Constructors and assignment operators コンストラクタと代入演算子
  6. Destructor デストラクタ
  7. All other functions (static and non-static member functions, and friend functions) その他のすべての関数 (static と非static メンバ関数、friend関数)
  8. All other data members (static and non-static) 上記以外の(静的/非静的)データメンバ

Do not put large method definitions inline in the class definition. クラス定義の中では、大きなメソッドの定義をインラインに行わないでください。 Usually, only trivial or performance-critical, and very short, methods may be defined inline. 通常は、些細であるか、または、パフォーマンスが重要な、非常に短い関数のみをインラインで定義します。 See Inline Functions for more details. より詳細はインライン関数で述べます。

関数

入力と出力

The output of a C++ function is naturally provided via a return value and sometimes via output parameters (or in/out parameters). C++関数の出力は、通常は戻り値経由で提供されますが、しばしば出力用(もしくは入出力用)の引数も使われます。

Prefer using return values over output parameters: they improve readability, and often provide the same or better performance. 出力用引数よりは素直な戻り値を用いる方が望ましいです。 可読性が向上し、パフォーマンスも同等以上に得られます。

Prefer to return by value or, failing that, return by reference. 戻り値はできるだけ値返しで返し、何らかの事情によりそれができないときは参照返しにします。 Avoid returning a pointer unless it can be null. ポインタ返しは、戻り値としてnullを取りうる場合のみ採用し、それ以外の場合は避けてください。

Parameters are either inputs to the function, outputs from the function, or both. 関数における引数は、関数への入力用、関数からの出力用、あるいはそれらの両方を行う入出力用のいずれかに分類されます。 Non-optional input parameters should usually be values or const references, while non-optional output and input/output parameters should usually be references (which cannot be null). 関数に渡す入力用引数のうち、入力必須とするものは通常は値渡しかconst参照渡しで宣言します。出力用および入出力用引数で必須のものは、通常は非const参照渡し(nullを不可とするため)で宣言します。 Generally, use std::optional to represent optional by-value inputs, and use a const pointer when the non-optional form would have used a reference. 入力用引数のうち、入力を必須としないものについては、std::optionalで包んで値渡しするか、(参照渡しをしたいのであれば)constポインタを使います。 Use non-const pointers to represent optional outputs and optional input/output parameters. 出力用および入出力用引数のうち、必須としないものには非constポインタを使います。

Avoid defining functions that require a const reference parameter to outlive the call, because const reference parameters bind to temporaries. const参照引数は一時オブジェクトを束縛することもできるため、関数の定義において、関数呼び出しから戻った後にも渡されたconst参照引数の参照先が存続していることを期待してはいけません。 Instead, find a way to eliminate the lifetime requirement (for example, by copying the parameter), or pass it by const pointer and document the lifetime and non-null requirements. かわりに、寿命が存続していなくてもよいように実装する(例えば内部で引数をコピーしておく等)か、もしくは、その引数をconstポインタ渡しとして、寿命と非null性に関する要件をドキュメントに残すようにしてください。

When ordering function parameters, put all input-only parameters before any output parameters. 関数引数の順番を決めるときは、すべての入力専用引数を、いかなる出力用引数よりも先に配置します。 In particular, do not add new parameters to the end of the function just because they are new; place new input-only parameters before the output parameters. 特に、関数に後から新しい引数を追加するときでも、新しく追加することを理由に最後に配置するようなことは避けてください。 つまり、入力専用引数が新しくても、出力引数よりは前に並べてください。 This is not a hard-and-fast rule. とはいえ、これらの引数の並び順は絶対厳守のルールというわけでもありません。 Parameters that are both input and output muddy the waters, and, as always, consistency with related functions may require you to bend the rule. 入力と出力の両方の役割を持つ引数は、明確な線引きが難しいものもあります。 また、関連する関数との一貫性を保つためにはこのルールを曲げる必要があるかもしれません。 Variadic functions may also require unusual parameter ordering. あるいは、可変長引数関数においても、通常とは異なる引数順序で並べることを必要とするでしょう。

関数は短く

Prefer small and focused functions. 関数は、短く、焦点を絞ります。

We recognize that long functions are sometimes appropriate, so no hard limit is placed on functions length. 時には、関数が長くとも、それが適切なこともありますので、関数の長さに関する固定の限界値は定めません。 If a function exceeds about 40 lines, think about whether it can be broken up without harming the structure of the program. 通常は、だいたい40行程度を超えたくらいで、プログラムの構造を害さずに、関数を分割することができないか考えてみてください。

Even if your long function works perfectly now, someone modifying it in a few months may add new behavior. ある長い関数が現時点では完璧に動いていたとしても、数ヶ月後に誰かがそれを変更して、新しい動作を足すかもしれません。 This could result in bugs that are hard to find. その結果として、見つけるのが困難なバグに繋がるかもしれません。 Keeping your functions short and simple makes it easier for other people to read and modify your code. 関数を短くシンプルに保っておくことで、コードが、より読みやすく、より変更しやすくなるでしょう。 Small functions are also easier to test. また、小さい関数は、その分テストも容易です。

You could find long and complicated functions when working with some code. 作業をしていると、長く複雑なコードに出くわすことがあります。 Do not be intimidated by modifying existing code: if working with such a function proves to be difficult, you find that errors are hard to debug, or you want to use a piece of it in several different contexts, consider breaking up the function into smaller and more manageable pieces. 既存のコードを変更することに怯えないでください。 そのコードを取り扱うのが困難であると感じたとき、エラーをデバッグすることが困難であると感じたときとき、あるいは関数の一部分だけを切り出して別のところで使いたいと思ったとき、その関数をより小さく扱いやすい複数のピースに分割できないか検討してみてください。

関数のオーバーロード

Use overloaded functions (including constructors) only if a reader looking at a call site can get a good idea of what is happening without having to first figure out exactly which overload is being called. コンストラクタを含め、関数をオーバーロードするときは、コード読者が呼び出し元のコードを読んだときに、具体的にどの関数が呼び出されるのか正確に把握せずとも、何が行われるのか予想できるようにしてください。

You may write a function that takes a const std::string& and overload it with another that takes const char*. たとえば、const std::string&を引数にとる関数とconst char*を引数にとる関数とを書くことができます。 However, in this case consider  std::string_view instead. (もっとも、このケースでは、かわりにstd::string_viewを検討すべきです。)

class MyClass {
 public:
  void Analyze(const std::string &text);
  void Analyze(const char *text, size_t textlen);
};

Overloading can make code more intuitive by allowing an identically-named function to take different arguments. 関数のオーバーロードを用いると、同じ関数名で異なる引数を受け入れる関数を定義することができるため、コードをより直感的にすることができます。 It may be necessary for templatized code, and it can be convenient for Visitors. この機能は、テンプレート化されたコードにおいて必須とされたり、また、ビジターパターンを実装するときにも同様に役立ったりします。

Overloading based on const or ref qualification may make utility code more usable, more efficient, or both. (See TotW 148 for more.) メンバ関数におけるconst修飾子や参照修飾子によるオーバーロードは、ユーティリティコードをより有用なものにしたり、効率的にしたり、またその両方の恩恵をもたらしたりします。 (詳しくは TotW 148 を見てください)

If a function is overloaded by the argument types alone, a reader may have to understand C++'s complex matching rules in order to tell what's going on. 関数が引数の型だけでオーバーロードされているとき、コードの読者がC++の複雑なマッチングルールを理解していないと、何が起こるのかわからないかもしれません。 Also many people are confused by the semantics of inheritance if a derived class overrides only some of the variants of a function. また、複数のオーバーロードを持つ仮想関数について、派生先のクラスで部分的にオーバーライドした場合の挙動は、多くの人を困惑させています。

You may overload a function when there are no semantic differences between variants. 関数は、同じ関数名をもつオーバーロード定義同士の間で互いに意味上の違いがないときに限り、オーバーロードしてもかまいません。 These overloads may vary in types, qualifiers, or argument count. これらのオーバーロードの中には、型が異なったり、修飾子が異なったり、引数の数が異なったりと、様々なものを含んでいます。 However, a reader of such a call must not need to know which member of the overload set is chosen, only that something from the set is being called. しかし、それを呼び出す側のコードの読者は、当該オーバーロードのセットのうちのいずれかが呼ばれていることまでわかればよく、具体的にどれが選ばれるのかを知る必要はありません。 If you can document all entries in the overload set with a single comment in the header, that is a good sign that it is a well-designed overload set. あるオーバーロードのセットについてヘッダーファイルでコメントを書くとき、すべてのオーバーロードについてまとめて1つのコメントで賄えたとしたら、そのことは、その関数オーバーロードのセットをうまくデザインできている証です。

デフォルト引数

Default arguments are allowed on non-virtual functions when the default is guaranteed to always have the same value. 関数が仮想関数ではなく、かつ、常にその値が同じ値になることを保証する場合に限って、関数引数にデフォルト値を与えてもかまいません。 Follow the same restrictions as for function overloading, and prefer overloaded functions if the readability gained with default arguments doesn't outweigh the downsides below. 関数のオーバーロードと同様の制限に従ってください。 また、デフォルト引数を用いることによって得られる可読性よりも、後述するデメリットの方が勝るような場合は、かわりに関数のオーバーロードを使いましょう。

Often you have a function that uses default values, but occasionally you want to override the defaults. 普段はデフォルトの値のまま使っている関数でも、時々別の値に変えて呼び出したいことがあります。 Default parameters allow an easy way to do this without having to define many functions for the rare exceptions. 引数にデフォルト値を与えることによって、このような"時々"のための関数をたくさん定義することなく、簡単にやりたいことを実現できます。 Compared to overloading the function, default arguments have a cleaner syntax, with less boilerplate and a clearer distinction between 'required' and 'optional' arguments. この方法は、関数をオーバーロードする場合に比べて、文法的にきれいで、定型文も少なく済み、さらに、各引数が必須なのか任意なのかをより明確に区別することができます。

Defaulted arguments are another way to achieve the semantics of overloaded functions, so all the reasons not to overload functions apply. 引数のデフォルト値を与える手法は、意味的には関数のオーバーロードの代替手段であるため、すべての関数をオーバーロードしない理由も適用されます。

The defaults for arguments in a virtual function call are determined by the static type of the target object, and there's no guarantee that all overrides of a given function declare the same defaults. 仮想関数呼び出し時の引数のデフォルト値は、ターゲットとするオブジェクトの静的な型に基づいて決定されますが、すべてのオーバーライドにおいて同じ値が宣言されている保証がありません。

Default parameters are re-evaluated at each call site, which can bloat the generated code. 引数のデフォルト値は、すべての呼び出し元で再評価されます。このため、生成されるコードのサイズが予想以上にふくれあがることがあります。 Readers may also expect the default's value to be fixed at the declaration instead of varying at each call. また、コードの読者も、関数の呼び出しごとにデフォルト値が変わるのではなく、宣言時点で決まった値に固定されていると考えるかもしれません。

Function pointers are confusing in the presence of default arguments, since the function signature often doesn't match the call signature. 関数ポインタを引数のデフォルト値として与えると、その記述の仕方に困惑するかもしれません。関数のシグネチャはしばしば、呼び出し時のシグネチャと一致しないことがあるからです。 Adding function overloads avoids these problems. 関数のオーバーロードであれば、これらの問題は回避することができます。

Default arguments are banned on virtual functions, where they don't work properly, and in cases where the specified default might not evaluate to the same value depending on when it was evaluated. 仮想関数に対する引数のデフォルト値は、意図に反する動作をすることがあるため、禁止とします。また、評価されるタイミング次第で異なる値になりうる引数のデフォルト値も禁止します。 (For example, don't write void f(int n = counter++); .) (たとえば、void f(int n = counter++);のようなコードは書いてはいけません。)

In some other cases, default arguments can improve the readability of their function declarations enough to overcome the downsides above, so they are allowed. それら以外のケースにおいて、デフォルト値を与えることで、そのデメリットを差し引いても関数宣言の可読性を高められる場合には、関数引数にデフォルト値を与えてもかまいません。 When in doubt, use overloads. 迷ったときには、関数のオーバーロードを選択してください。

戻り値の型を後置する関数宣言構文

Use trailing return types only where using the ordinary syntax (leading return types) is impractical or much less readable. 戻り値の型を後置する関数宣言の構文は、従来からある通常の関数宣言構文(戻り値の型に始まる構文)を使うのが非現実的であったり、あるいは、その構文では可読性が非常に劣ってしまう場合に限定して用います。

C++ allows two different forms of function declarations. C++の関数宣言には、2種類の異なる構文が存在します。 In the older form, the return type appears before the function name. For example: 従来からある構文では、次のように、戻り値の型を関数名の前に記述します。

int foo(int x);

The newer form uses the auto keyword before the function name and a trailing return type after the argument list. 新しい形の構文では、まずautoキーワードを関数名の前に置き、関数名、引数リストと続けた後に戻り値の型を書きます。 For example, the declaration above could equivalently be written: 例として、先ほどの宣言と等価な宣言は次のように書けます。

auto foo(int x) -> int;

The trailing return type is in the function's scope. 後置される戻り値の型は関数内スコープになります。 This doesn't make a difference for a simple case like int but it matters for more complicated cases, like types declared in class scope or types written in terms of the function parameters. intのような単純なケースではこれらの間に違いはありませんが、より複雑な場合、たとえば、型がクラススコープで宣言されている場合や、型が関数の引数リスト内の語によって表現される場合は、この違いが重要になってきます。

Trailing return types are the only way to explicitly specify the return type of a lambda expression. 戻り値の型を後置する構文は、ラムダ式の戻り値の型を明示できる唯一の方法です。 In some cases the compiler is able to deduce a lambda's return type, but not in all cases. コンパイラによってラムダ式の戻り値の型を推論できる場合もありますが、常に可能というわけではありません。 Even when the compiler can deduce it automatically, sometimes specifying it explicitly would be clearer for readers. あるいは、コンパイラによって自動的に型が推論できる場合であっても、型を明示的に記述することで、コードの可読性が高まる場合もあります。

Sometimes it's easier and more readable to specify a return type after the function's parameter list has already appeared. 通常の関数においても、戻り値の型を引数リストの後に置くことで、コードがより簡単になり、可読性が高まることがあります。 This is particularly true when the return type depends on template parameters. これは、特に、戻り値の型がテンプレートパラメータによって決まる場合が当てはまります。 For example: 次に例を示します。

    template <typename T, typename U>
    auto add(T t, U u) -> decltype(t + u);
versus これに比べて、次のコードはどうでしょうか。
    template <typename T, typename U>
    decltype(declval<T&>() + declval<U&>()) add(T t, U u);

Trailing return type syntax is relatively new and it has no analogue in C++-like languages such as C and Java, so some readers may find it unfamiliar. 戻り値の型を後置する関数宣言構文は、比較的新しく、C言語やJavaなどの他のC++系言語を見ても類似の構文がありません。このため、コードの読者にとって馴染みが薄いかもしれません。

Existing code bases have an enormous number of function declarations that aren't going to get changed to use the new syntax, so the realistic choices are using the old syntax only or using a mixture of the two. 既存のコードベースには既に膨大な数の関数宣言がありますが、それらのすべてが新しい構文に置き換わることはありません。 このため、現実的な選択肢は、古い構文だけを使い続けるのか、新旧両方の構文を混ぜて使っていくかのどちらかです。 Using a single version is better for uniformity of style. そして、スタイルの一様性を保つためには、1種類だけを使うことが望ましいです。

In most cases, continue to use the older style of function declaration where the return type goes before the function name. ほとんどの場合において、従来ながらの、戻り値の型を関数名の前に書く構文を使い続けてください。 Use the new trailing-return-type form only in cases where it's required (such as lambdas) or where, by putting the type after the function's parameter list, it allows you to write the type in a much more readable way. 新しい、戻り値の型を後置する関数宣言構文は、ラムダ式などにおいてその構文を必須とする場合や、あるいは、引数リストの後に戻り値の型を置くことによって型が大幅に読みやすくなる場合に限って使用してください。 The latter case should be rare; it's mostly an issue in fairly complicated template code, which is discouraged in most cases. とはいえ、後者の状況はレアケースなはずです。そのような状況のほとんどが、そのテンプレートコードが複雑すぎることに起因しており、通常、そのような複雑なテンプレートは非推奨だからです。

Google特有のマジック

There are various tricks and utilities that we use to make C++ code more robust, and various ways we use C++ that may differ from what you see elsewhere. Googleでは、C++のコードをより堅牢にするために、様々なトリックやユーティリティが使われています。 これらの手法の中には、一般的なC++の使い方とは異なる部分があるかもしれません。

オブジェクトの所有権とスマートポインタ

Prefer to have single, fixed owners for dynamically allocated objects. 動的に確保されるオブジェクトは、単一の、固定された所有者に属するようにします。 Prefer to transfer ownership with smart pointers. オブジェクトの所有権を移すときには、スマートポインタを使ってそれを表現します。

"Ownership" is a bookkeeping technique for managing dynamically allocated memory (and other resources). 「所有権」とは、動的に確保されるメモリ(や、その他のリソース)を管理するための帳簿的なテクニックの一つです。 The owner of a dynamically allocated object is an object or function that is responsible for ensuring that it is deleted when no longer needed. 動的に確保されるオブジェクトは、1つのオブジェクトもしくは1つの関数に所有され、その所有者であるオブジェクトや関数は、所有するオブジェクトが不要になったとき、確実にそれを解放する責任を負います。 Ownership can sometimes be shared, in which case the last owner is typically responsible for deleting it. 所有権は複数の所有者の間で共有されることもあり、この場合には、最後の所有者が解放の責任を負うのが典型的です。 Even when ownership is not shared, it can be transferred from one piece of code to another. あるいは、所有権を共有まではせずとも、あるコードから他のコードへと、オブジェクトの所有権が移されることもあります。

"Smart" pointers are classes that act like pointers, e.g., by overloading the * and -> operators. スマートポインタ」とは、ポインタのように振る舞うクラスの総称で、たとえば、演算子*->をオーバーロードしています。 Some smart pointer types can be used to automate ownership bookkeeping, to ensure these responsibilities are met. スマートポインタの中には、所有権管理を自動的に行い、解放責任を確実に果たすために使えるものがあります。 std::unique_ptr is a smart pointer type introduced in C++11, which expresses exclusive ownership of a dynamically allocated object; the object is deleted when the std::unique_ptr goes out of scope. std::unique_ptrは、C++11で導入されたスマートポインタのひとつで、動的確保されるオブジェクトに対して排他的な所有権を持つことを表現するために使われます。 std::unique_ptrによって所有されるオブジェクトは、std::unique_ptrがスコープ外となったときに自動的に解放されます。 It cannot be copied, but can be moved to represent ownership transfer. std::unique_ptrはコピーできませんが、所有権を移すためにムーブすることはできます。 std::shared_ptr is a smart pointer type that expresses shared ownership of a dynamically allocated object. std::shared_ptrは、動的確保されたオブジェクトの所有権を他と共有することを表現するために使われるスマートポインタです。 std::shared_ptrs can be copied; ownership of the object is shared among all copies, and the object is deleted when the last std::shared_ptr is destroyed. std::shared_ptrはコピーすることができ、オブジェクトの所有権は、それらのすべてのコピー同士の間で共有されます。最後のstd::shared_ptrインスタンスが破壊されるときに、共有しているオブジェクトが解放されます。

If dynamic allocation is necessary, prefer to keep ownership with the code that allocated it. 動的にオブジェクトを確保する必要があるときは、それを行うコードにオブジェクトの所有権を持たせるようにしましょう。 If other code needs access to the object, consider passing it a copy, or passing a pointer or reference without transferring ownership. 他のコードからそのオブジェクトにアクセスしたいときは、オブジェクトをコピーして渡す方法か、所有権を移さずにポインタか参照を渡す方法を検討してください。 Prefer to use std::unique_ptr to make ownership transfer explicit. 所有権を移すときは、それを明示的に表現するために、std::unique_ptrを使いましょう。 For example: 以下に例を示します。

std::unique_ptr<Foo> FooFactory();
void FooConsumer(std::unique_ptr<Foo> ptr);

Do not design your code to use shared ownership without a very good reason. オブジェクトの所有権を共有させる設計は、非常に良い理由がない限り、避けてください。 One such reason is to avoid expensive copy operations, but you should only do this if the performance benefits are significant, and the underlying object is immutable (i.e., std::shared_ptr<const Foo>). ここでいう理由には、たとえばオブジェクトをコピーする高いコストを避けたいから、といったものが挙げられます。しかし、その場合であっても、そのパフォーマンス上のメリットが非常に大きく、かつ、対象となるオブジェクトが不変である(すなわち、std::shared_ptr<const Foo>)場合に限定すべきです。 If you do use shared ownership, prefer to use std::shared_ptr. これらを踏まえて、所有権を共有させることを選ぶ場合は、std::shared_ptrを使いましょう。

Never use std::auto_ptr. std::auto_ptrの使用は禁止します。 Instead, use std::unique_ptr. かわりに、std::unique_ptrを使ってください。

cpplint

Use cpplint.py to detect style errors. cpplint.pyを使ってスタイルを診断しましょう。

cpplint.py is a tool that reads a source file and identifies many style errors. cpplint.pyは、ソースファイルを読み込ませると、スタイルに関するたくさんのエラーを識別してくれるツールです。 It is not perfect, and has both false positives and false negatives, but it is still a valuable tool. このツールは完璧ではなく、ときに誤検出したり、問題を見逃したりもしますが、それでも十分に有用であることは間違いありません。 False positives can be ignored by putting // NOLINT at the end of the line or // NOLINTNEXTLINE in the previous line. 偽陽性の誤判定がなされる場合は、行末に// NOLINTを書くか、直前の行に// NOLINTNEXTLINEを書くことで、無視させることができます。

Some projects have instructions on how to run cpplint.py from their project tools. プロジェクトによっては、プロジェクトツールでcpplint.pyを起動する手順が用意されている場合があります。 If the project you are contributing to does not, you can download cpplint.py separately. それ以外の場合、cpplint.pyから個別にダウンロードすることができます。

その他のC++の機能

右辺値参照(rvalue reference)

Use rvalue references only in certain special cases listed below. 右辺値参照は、以下で説明するような特殊な場合に限り使用します。

Rvalue references are a type of reference that can only bind to temporary objects. 右辺値参照(rvalue reference)とは、一時オブジェクトのみを束縛する参照のことです。 The syntax is similar to traditional reference syntax. その文法は従来からある参照の文法に似ています。 For example, void f(std::string&& s); declares a function whose argument is an rvalue reference to a std::string. たとえば、void f(string&& s);は、std::stringへの右辺値参照を引数にとる関数を宣言しています。

When the token '&&' is applied to an unqualified template argument in a function parameter, special template argument deduction rules apply. 関数の仮引数において、修飾子のないテンプレート引数に && が使われた場合、特殊なテンプレート引数推論ルールが適用されます。 Such a reference is called a forwarding reference. このような特殊な参照は、「転送参照(Forwarding Reference)」と呼ばれます。(訳注:従来はユニバーサル参照(Universal Reference)と呼ばれていましたが、C++17で転送参照という語が定められました)

Do not use rvalue references (or apply the && qualifier to methods), except as follows: 右辺値参照(や、メソッドの&&参照修飾子)は、以下の場合に限り使用できます。それ以外の場合は使ってはいけません。

フレンド

We allow use of friend classes and functions, within reason. 合理的な範囲内であれば、friendクラスやfriend関数を使ってもかまいません。

Friends should usually be defined in the same file so that the reader does not have to look in another file to find uses of the private members of a class. フレンドに指定する対象は、通常は同じファイル内で定義してください。 そうすることで、コードの読者は、それらのフレンドがクラスのプライベートメンバをどう扱うのか、他のファイルに探しに行かずともよくなります。 A common use of friend is to have a FooBuilder class be a friend of Foo so that it can construct the inner state of Foo correctly, without exposing this state to the world. よくあるフレンドの使い方は、たとえば、FooBuilderクラスをFooクラスのフレンドにして、Fooの内部状態を全世界に晒すことなくFooBuilderに正しく構築させられるようにするといったパターンです。 In some cases it may be useful to make a unittest class a friend of the class it tests. 他にも、たとえば、クラスのユニットテストを担うクラスをフレンド指定しておくと便利なこともあります。

Friends extend, but do not break, the encapsulation boundary of a class. フレンドの仕組みは、クラスのカプセル化の境界を壊すことなく拡張することができます。 In some cases this is better than making a member public when you want to give only one other class access to it. ある特定のクラスにだけメンバへのアクセス権を与えたいとき、そのメンバを単にpublicにするよりも、フレンドを用いる方が適切な場合があります。 However, most classes should interact with other classes solely through their public members. ただし、原則としては、ほとんどのクラス間のやりとりはpublicメンバを通してのみ行うようにしてください。

例外

We do not use C++ exceptions. 私たちはC++の例外を使いません。

On their face, the benefits of using exceptions outweigh the costs, especially in new projects. 表面的には、特に新規のプロジェクトであれば、例外を有効にするメリットがコストより上回るでしょう。 However, for existing code, the introduction of exceptions has implications on all dependent code. しかし、その一方で、既存のコードにおいて例外を導入しようとすると、そのすべての依存コードに影響を与えてしまいます。 If exceptions can be propagated beyond a new project, it also becomes problematic to integrate the new project into existing exception-free code. このため、もし何らか新しいプロジェクトを採用したい場合でも、そのプロジェクトから例外が伝播してくる可能性があるとなると、それらを既存の例外未使用のコードと統合することは難しい問題になります。 Because most existing C++ code at Google is not prepared to deal with exceptions, it is comparatively difficult to adopt new code that generates exceptions. そして、Googleの既存のC++コードは、そのほとんどにおいて、例外を扱う準備ができていません。このため、新しいコードが例外を生成するのであれば、それらを採用することは比較的困難なことです。

Given that Google's existing code is not exception-tolerant, the costs of using exceptions are somewhat greater than the costs in a new project. 現状のGoogleの既存のコードは例外を扱えないため、これらのコードで新たに例外を扱うコストは、新規のプロジェクトで例外を扱う場合に比べて、いくぶん大きなものになります。 The conversion process would be slow and error-prone. 例外への対応には時間がかかるでしょうし、ミスも起こりやすいでしょう。 We don't believe that the available alternatives to exceptions, such as error codes and assertions, introduce a significant burden. 私たちは、例外のかわりに、エラーコードやアサーションといった代替手段を使うことが、大きな負担をもたらすとは考えていません。

Our advice against using exceptions is not predicated on philosophical or moral grounds, but practical ones. このガイドで述べている例外に関するアドバイスは、哲学的あるいは道徳的な根拠によるものではなく、現実的な根拠に基づくものです。 Because we'd like to use our open-source projects at Google and it's difficult to do so if those projects use exceptions, we need to advise against exceptions in Google open-source projects as well. 私たちは、Googleでオープンソースプロジェクトを使いたいと考えています。しかし、新しいプロジェクトで例外が扱われているとそれを採用するのが難しくなってしまいます。このため、私たちは、Googleのオープンソースプロジェクトに対しても同様に例外を避けるようにアドバイスする必要があります。 Things would probably be different if we had to do it all over again from scratch. もし、最初からすべてのことをやり直すとしたら、何かが違っていたかもしれません。

This prohibition also applies to exception handling related features such as std::exception_ptr and std::nested_exception. これらの禁止ルールは、std::exception_ptrstd::nested_exceptionなどの、例外処理に関する機能についても同様に適用します。

There is an exception to this rule (no pun intended) for Windows code. なお、例外についてはWindowsのコードに関する例外があります(ダジャレじゃないですよ)。

noexcept

Specify noexcept when it is useful and correct. 有用かつ正しいときnoexceptを指定します。

The noexcept specifier is used to specify whether a function will throw exceptions or not. noexcept指定子は、関数が例外を投げるか否かを指定するために使われます。 If an exception escapes from a function marked noexcept, the program crashes via std::terminate. noexceptとマークされた関数から例外が抜け出すと、プログラムは std::terminate を介してクラッシュします。

The noexcept operator performs a compile-time check that returns true if an expression is declared to not throw any exceptions. noexcept演算子は、与えられた式の宣言から、式が一切の例外を投げないと判定される場合に真となるコンパイル時のチェックを実行します。

You may use noexcept when it is useful for performance if it accurately reflects the intended semantics of your function, i.e., that if an exception is somehow thrown from within the function body then it represents a fatal error. 関数の意図するセマンティクスを正確に反映している場合、すなわち、もし例外が投げられたのであれば即それは致命的なエラーを表すという場合において、noexceptがパフォーマンスに貢献するのであれば、これを使用してかまいません。 You can assume that noexcept on move constructors has a meaningful performance benefit. ムーブコンストラクタのnoexceptには、有意なパフォーマンス上の利点があると考えてかまいません。 If you think there is significant performance benefit from specifying noexcept on some other function, please discuss it with your project leads. それ以外の関数において、noexceptによって大きなパフォーマンス上のメリットが得られると考える場合は、プロジェクトリーダーと相談して決めてください。

Prefer unconditional noexcept if exceptions are completely disabled (i.e., most Google C++ environments). 例外を完全に無効にしている環境(すなわち、ほとんどのGoogleのC++環境)では、条件のないnoexceptを使ってください。 Otherwise, use conditional noexcept specifiers with simple conditions, in ways that evaluate false only in the few cases where the function could potentially throw. それ以外の場合は、シンプルな条件とともに条件付きのnoexcept指定子を使用してください。 これらで指定する条件は、関数が潜在的に例外を投げる可能性のある少数のケースでのみ偽に評価されるようにします。 The tests might include type traits check on whether the involved operation might throw (e.g., std::is_nothrow_move_constructible for move-constructing objects), or on whether allocation can throw (e.g., absl::default_allocator_is_nothrow for standard default allocation). この条件子におけるテストには、たとえば、呼び出す操作が例外を投げるか否か(ムーブ生成するオブジェクトに対するstd::is_nothrow_move_constructible)や、メモリ確保操作が例外を投げるか否か(デフォルトのアロケート操作に対するabsl::default_allocator_is_nothrow)などの、型トレイトに関するチェックなどが含まれるでしょう。 Note in many cases the only possible cause for an exception is allocation failure (we believe move constructors should not throw except due to allocation failure), and there are many applications where it’s appropriate to treat memory exhaustion as a fatal error rather than an exceptional condition that your program should attempt to recover from. なお、多くの場合において、例外の唯一の原因はアロケーション(メモリやリソース確保)操作の失敗であることに注意してください。(ムーブコンストラクタはリソース確保操作の失敗以外で例外を投げるべきではありません。) そして、このようなメモリの枯渇は、多くのアプリケーションにおいて、プログラムが回復を試みるべき状況ではなく、単なる致命的なエラーとして扱う方が適切であることも多いです。 Even for other potential failures you should prioritize interface simplicity over supporting all possible exception throwing scenarios: instead of writing a complicated noexcept clause that depends on whether a hash function can throw, for example, simply document that your component doesn’t support hash functions throwing and make it unconditionally noexcept. その他の潜在的に起こりえるエラーに関しても、考えられるすべての種類の例外シナリオに対応しようとするのではなく、インターフェースをシンプルに保つことを優先してください。たとえば、与えられたハッシュ関数が例外を投げるか否かを判定するための複雑なnoexceptクロージャを書くのではなく、そのかわりに、その関数のドキュメント等で例外を投げるハッシュ関数をサポートしないことを表明し、単に、条件なしのnoexcept指定子でマークしてしまうのもひとつのやり方です。

実行時型情報(RTTI)

Avoid using run-time type information (RTTI). 実行時型情報(RTTI)を使うのは避けます。

RTTI allows a programmer to query the C++ class of an object at run-time. RTTI(Run-Time Type Information:実行時型情報)を用いると、プログラマーは実行時にオブジェクトのC++クラスを調べることができます。 This is done by use of typeid or dynamic_cast. これは、typeiddynamic_castを使うことで実現されます。

The standard alternatives to RTTI (described below) require modification or redesign of the class hierarchy in question. RTTIに対する標準的な代替手段(後述)を使おうとすると、対象とするクラスの階層構造の変更や再設計が必要になってしまいます。 Sometimes such modifications are infeasible or undesirable, particularly in widely-used or mature code. 既にそのコードが広く使われていたり成熟していたりすると、このような変更を施すことはもはや実現不可能であったり、あるいは望ましくないということがあります。

RTTI can be useful in some unit tests. RTTIはユニットテストにおいても有用な場面があります。 For example, it is useful in tests of factory classes where the test has to verify that a newly created object has the expected dynamic type. たとえば、ファクトリクラスをテストするとき、正しい型のオブジェクトが生成できていることを検証するためにはRTTIが使えるでしょう。 It is also useful in managing the relationship between objects and their mocks. また、オブジェクトとそのモックとの関係を管理するのにも有用です。

RTTI is useful when considering multiple abstract objects. RTTIは、多数の抽象オブジェクトを考えるときにも有用です。 Consider 以下の例を考えてみてください。

bool Base::Equal(Base* other) = 0;
bool Derived::Equal(Base* other) {
  Derived* that = dynamic_cast<Derived*>(other);
  if (that == nullptr)
    return false;
  ...
}

Querying the type of an object at run-time frequently means a design problem. 実行時に頻繁にオブジェクトの型を調べる必要が生じているのであれば、その事実は、プログラムに設計上の問題があることを示唆しています。 Needing to know the type of an object at runtime is often an indication that the design of your class hierarchy is flawed. 実行時にオブジェクトの型を知る必要があるということは、しばしば、クラス階層構造の設計に欠陥があることを示しています。

Undisciplined use of RTTI makes code hard to maintain. 無秩序にRTTIを濫用すると、コードのメンテナンスが困難になります。 It can lead to type-based decision trees or switch statements scattered throughout the code, all of which must be examined when making further changes. このようなコードにおいては、型に基づく決定木やswitch文がコード中のあちこちに散乱してしまいがちになり、さらに、将来コードを変更するときには、それらのすべてをチェックして回る必要に迫られます。

RTTI has legitimate uses but is prone to abuse, so you must be careful when using it. RTTIには妥当な使い方もありますが、やや逸脱した使われ方をする傾向にあります。RTTIを扱うときは十分注意してください。 You may use it freely in unittests, but avoid it when possible in other code. ユニットテストにおいては、自由にRTTIを使ってもかまいません。それ以外のコードにおいては可能な限り避けてください。 In particular, think twice before using RTTI in new code. 特に、新しいコードにおいては、RTTIを使おうとする前に、もう一度よく考えてみてください。 If you find yourself needing to write code that behaves differently based on the class of an object, consider one of the following alternatives to querying the type: もし、オブジェクトのクラスに応じて挙動を変えるコードを書く必要が生じたときでも、すぐにRTTIで型を調べようとせず、かわりに次のいずれかの代替手段が採用できないか検討してみてください。

When the logic of a program guarantees that a given instance of a base class is in fact an instance of a particular derived class, then a dynamic_cast may be used freely on the object. プログラムのある地点において、プログラム構造上、ある基底クラスのインスタンスが、実際にはある特定の派生クラスのインスタンスであると保証できる場合は、そのオブジェクトに対してdynamic_castを使ってもかまいません。 Usually one can use a static_cast as an alternative in such situations. 通常、このような場合においては、代替手段としてstatic_castを使うこともできます。

Decision trees based on type are a strong indication that your code is on the wrong track. 型による分岐が必要になったとき、その事実は、コードが間違った方向に進んでいることを強く示唆しています。

if (typeid(*data) == typeid(D1)) {
  ...
} else if (typeid(*data) == typeid(D2)) {
  ...
} else if (typeid(*data) == typeid(D3)) {
...

Code such as this usually breaks when additional subclasses are added to the class hierarchy. このようなコードは、大抵の場合、クラスの階層構造に新たな派生クラスが増えたときに破綻してしまいます。 Moreover, when properties of a subclass change, it is difficult to find and modify all the affected code segments. さらに、既存の派生クラスの性質が変わったときには、影響のあるすべてのコードを検索して変更しなければなりませんが、それらを正確に行うのは非常に難しいでしょう。

Do not hand-implement an RTTI-like workaround. なお、RTTIのようなものを自前で実装してはいけません。 The arguments against RTTI apply just as much to workarounds like class hierarchies with type tags. ここまでのRTTIに関する議論は、何らかの自作の仕組み、たとえばオブジェクトに型を表すタグをつけて識別する手法などであっても同様に当てはまります。 Moreover, workarounds disguise your true intent. その上、そのような回避策を採用すると、真の意図が見えにくくなってしまいます。

キャスト

Use C++-style casts like static_cast<float>(double_value), or brace initialization for conversion of arithmetic types like int64_t y = int64_t{1} << 42. キャストには、static_cast<float>(double_value)のようなC++スタイルのキャストを使います。 算術型の変換には、int64_t y = int64_t{1} << 42のような、波括弧初期化を使います。 Do not use cast formats like (int)x unless the cast is to void. voidへのキャストを除いて(int)xの形のキャストは使ってはいけません。 You may use cast formats like T(x) only when T is a class type. なお、型Tがクラスであるときに限り、T(x)のような形のキャストを使用してもかまいません。

C++ introduced a different cast system from C that distinguishes the types of cast operations. C++にはC言語とは異なるキャストシステムが導入されており、C++のキャストはその操作の種類によって区別されます。

The problem with C casts is the ambiguity of the operation; sometimes you are doing a conversion (e.g., (int)3.5) and sometimes you are doing a cast (e.g., (int)"hello"). C言語のキャストの問題点は、その操作が曖昧であることです。 これらは、ときには変換(例:(int)3.5)であり、ときにはキャスト(例:(int)"hello")を表しています。 Brace initialization and C++ casts can often help avoid this ambiguity. 波括弧初期化とC++のキャストを使えば、このような曖昧さはなくなります。 Additionally, C++ casts are more visible when searching for them. 加えて、C++のキャストを使っていれば、それら検索するときにも見つけやすくもなります。

The C++-style cast syntax is verbose and cumbersome. C++スタイルのキャストの文法は長くて面倒くさいです。

In general, do not use C-style casts. 原則として、C言語スタイルのキャストは使ってはいけません。 Instead, use these C++-style casts when explicit type conversion is necessary. 明示的な型変換を必要とするときは、C言語スタイルのキャストではなく、C++スタイルのキャストを使ってください。

See the RTTI section for guidance on the use of dynamic_cast. dynamic_castに関するガイドについては実行時型情報(RTTI)のセクションも参照してください。

ストリーム

Use streams where appropriate, and stick to "simple" usages. 適切な場合には、後述するシンプルな使い方に限り、ストリームを使ってもかまいません。 Overload << for streaming only for types representing values, and write only the user-visible value, not any implementation details. ストリーム演算子<<のオーバーロードは、対象の型のオブジェクトが何らか値を表現する場合に限ります。また、その実装を、値を人間が判読可能な形にフォーマットするだけにとどめ、それ以上の詳細な実装を持たないようにしてください。

Streams are the standard I/O abstraction in C++, as exemplified by the standard header <iostream>. ストリームは、標準ヘッダー<iostream>でも例示される、C++における標準的な入出力の抽象です。 They are widely used in Google code, mostly for debug logging and test diagnostics. Googleのコードにおいても、ストリームは、デバッグログ出力やテスト診断結果出力などを目的として広く使われています。

The << and >> stream operators provide an API for formatted I/O that is easily learned, portable, reusable, and extensible. C++のストリームは、演算子<<>>によって、学びやすさ、移植性、再利用可能性、拡張性などの面で優れた、フォーマット済み入出力を行うAPIを提供します。 printf, by contrast, doesn't even support std::string, to say nothing of user-defined types, and is very difficult to use portably. これとは対照的に、printf系のAPIでは、ユーザー定義型はおろか、std::stringへの対応すらなく、その使い方についても、正しく移植性を保って使うことが非常に難しいです。 printf also obliges you to choose among the numerous slightly different versions of that function, and navigate the dozens of conversion specifiers. さらに、printf系のAPIには、微妙に異なるたくさんのバージョンが存在し、その変換指定子も非常にたくさんの種類があります。printfを使うときは、常に、それらの中から適切なものを選んで、適切に使うことを強制されることになります。

Streams provide first-class support for console I/O via std::cin, std::cout, std::cerr, and std::clog. ストリームは、std::cinstd::coutstd::cerrstd::clogを通して、最上級のコンソール入出力をサポートします。 The C APIs do as well, but are hampered by the need to manually buffer the input. もちろん、C言語のAPIを用いても同様のことは実現できるのですが、その場合には、入力を手動でバッファする必要があるなど、いくぶん面倒にはなります。

Use streams only when they are the best tool for the job. ストリームは、それが目的を果たすための最良のツールであるという場合に限り採用しましょう。 This is typically the case when the I/O is ad-hoc, local, human-readable, and targeted at other developers rather than end-users. ストリームが適している典型例としては、(エンドユーザー向けではなく)他の開発者によって利用されることを想定した、アドホックで、局所的な、人間が判読可能な入出力を行いたい場合が相当します。 Be consistent with the code around you, and with the codebase as a whole; if there's an established tool for your problem, use that tool instead. ただし、周りのコードやコードベース全体との一貫性は保つようにしてください。このような目的を果たす手段として、プロジェクトで既に別の方法が確立されているのであれば、それらに倣ってください。 In particular, logging libraries are usually a better choice than std::cerr or std::clog for diagnostic output, and the libraries in absl/strings or the equivalent are usually a better choice than std::stringstream. 特に、診断系の出力を行う用途では、通常、単にstd::cerrstd::clogを使うよりも、ログ出力に特化したライブラリを用いる方が適切です。 また、std::stringstreamについても、それらのかわりにabsl/stringsや同等のライブラリを使う方がよいでしょう。

Avoid using streams for I/O that faces external users or handles untrusted data. 外部ユーザーのための入出力や、信頼できないデータを扱うときは、ストリームを使うのは避けてください。 Instead, find and use the appropriate templating libraries to handle issues like internationalization, localization, and security hardening. これらの用途では、ストリームではなく、多言語化に対応していて、かつ、セキュリティ的にも強固な、何らかの適切なテンプレートエンジンを探し出し、それを使うようにしてください。

If you do use streams, avoid the stateful parts of the streams API (other than error state), such as imbue(), xalloc(), and register_callback(). これらのことを踏まえて、それでもストリームを使うのであれば、その使い方において、エラー状態以外の内部状態を変更するストリームAPI(たとえば、imbue()xalloc()register_callback()など)を使うのを避けてください。 Use explicit formatting functions (such as absl::StreamFormat()) rather than stream manipulators or formatting flags to control formatting details such as number base, precision, or padding. 出力時の基数、精度、出力幅などを変更したいときは、ストリームマニピュレータやフラグなどのかわりに、明示的なフォーマット関数(たとえばabsl::StreamFormat())を使ってください。

Overload << as a streaming operator for your type only if your type represents a value, and << writes out a human-readable string representation of that value. 独自の型に対するストリーム演算子<<のオーバーロードは、その型のオブジェクトが何らかの値を表す場合に限定し、その演算子<<の定義において、オブジェクトが表す値を人間が判読可能な文字列表現に書き出す実装を行ってください。 Avoid exposing implementation details in the output of <<; if you need to print object internals for debugging, use named functions instead (a method named DebugString() is the most common convention). また、演算子<<によって、クラス内部実装の詳細を公開してしまわないように気をつけてください。 たとえば、デバッグ用途でオブジェクトの内部状態を出力したいときは、演算子<<ではなく、名前付きの関数を使ってください(この目的では、DebugString()という名前のメンバ関数を持たせるのが、もっとも一般的な慣習です)。

前置インクリメントと前置デクリメント

Use the prefix form (++i) of the increment and decrement operators unless you need postfix semantics. インクリメント演算子とデクリメント演算子は、後置(i++)する必要がない限り、前置(++i)します。

When a variable is incremented (++i or i++) or decremented (--i or i--) and the value of the expression is not used, one must decide whether to preincrement (decrement) or postincrement (decrement). 変数をインクリメント(++iもしくはi++)あるいはデクリメント(--iもしくはi--)するとき、その式の結果が使われない場合に、演算子を前置するか後置するか決めなければなりません。

A postfix increment/decrement expression evaluates to the value as it was before it was modified. 演算子を後置する形(i++)の式は、更新前の値に評価されます。 This can result in code that is more compact but harder to read. この評価結果を用いるコードは、コードをコンパクトにできる場合がありますが、読みにくくもなります。 The prefix form is generally more readable, is never less efficient, and can be more efficient because it doesn't need to make a copy of the value as it was before the operation. 一方で、演算子を前置する形(++i)は一般に読みやすく、決して非効率になることもありません。むしろ、操作前の値のコピーをとっておく必要がない分、生成されるコードがより効率的になることもあります。

The tradition developed, in C, of using post-increment, even when the expression value is not used, especially in for loops. 特にC言語での開発において、forループなどの式の結果が使われない場合でも、伝統的に、演算子を後置する形(i++)が使われてきました。 Some find post-increment easier to read, since the "subject" (i) precedes the "verb" (++), just like in English. この形は、英文法の語順と同じ、主語(i)の後に動詞(++)が続く形をしているため、こちらの方が読みやすいと感じる人もいるでしょう。

Use prefix increment/decrement, unless the code explicitly needs the result of the postfix increment/decrement expression. コードにおいて、後置インクリメント(i++)・後置デクリメント(i--)の式の結果を明示的に必要とする場合を除き、常に前置インクリメント(++i)・前置デクリメント(--i)を使用してください。

constの使い方

In APIs, use const whenever it makes sense. APIを定義するとき、理に適っているのならばいつでも常にconstを使います。 constexpr is a better choice for some uses of const. さらに、constよりもconstexprを用いる方が適切な場合もあります。

Declared variables and parameters can be preceded by the keyword const to indicate the variables are not changed (e.g., const int foo). 変数宣言や引数宣言では、const int fooのように、変数名の前にconstキーワードを前置することで、それらの変数が不変であることを示すことができます。 Class functions can have the const qualifier to indicate the function does not change the state of the class member variables (e.g., class Foo { int Bar(char c) const; };). また、クラスのメンバ関数の宣言において、class Foo { int Bar(char c) const; };のように、const修飾子をつけることで、その関数がクラスのメンバ変数の状態を変更しないことを示すことができます。

Easier for people to understand how variables are being used. const修飾された変数は不変であるため、プログラムにおけるその変数の扱われ方に関して、コードを理解しやすくなります。 Allows the compiler to do better type checking, and, conceivably, generate better code. また、コンパイル時において、よりよい型チェックを行うことができ、場合によって、より効率的なコードを生成できることがあります。 Helps people convince themselves of program correctness because they know the functions they call are limited in how they can modify your variables. 関数を呼ぶ際、その引数がconstであれば、変数が関数によって変更される心配がないため、プログラムの正当性について納得しやすくなります。 Helps people know what functions are safe to use without locks in multi-threaded programs. また、メンバ関数に対するconst修飾子はマルチスレッドプログラムにおいて、どの関数をロックなしに呼び出せるのか判断するための材料にもなります。

const is viral: if you pass a const variable to a function, that function must have const in its prototype (or the variable will need a const_cast). constは伝染します。 const変数を関数に渡すときは、関数宣言においても引数がconst修飾されている必要があり、さもなくば、const_castを必要とします。 This can be a particular problem when calling library functions. これは、特に、ライブラリ関数を呼び出すときに問題となることがあります。

We strongly recommend using const in APIs (i.e., on function parameters, methods, and non-local variables) wherever it is meaningful and accurate. APIの定義において (すなわち、関数引数やメソッド、非ローカル変数の宣言において)、意味が通り、かつ、正しいときは、いつでも常にconstをつけることを強く推奨します。 This provides consistent, mostly compiler-verified documentation of what objects an operation can mutate. これらのconst修飾子は、対象とする操作がどのオブジェクトを変更しうるのかに関する、一貫した、かつ、コンパイラによって検証済みでもあるドキュメントの役割を果たします。 Having a consistent and reliable way to distinguish reads from writes is critical to writing thread-safe code, and is useful in many other contexts as well. このような、読み込みと書き込みとを、一貫性と信頼性を持って区別できる手段は、特にスレッドセーフなコードを書くときには必要不可欠ですし、また、それ以外の多くの文脈においても同様に有用ですしょう。 In particular: 特に以下の事項を確認してください。

Using const on local variables is neither encouraged nor discouraged. ローカル変数にconstをつけるか否かは、推奨も非推奨もしません。

All of a class's const operations should be safe to invoke concurrently with each other. クラスのすべてのconstな操作は、それらが互いに同時に呼び出されても安全であるようにしてください。 If that's not feasible, the class must be clearly documented as "thread-unsafe". そのようにできない場合は、そのクラスがスレッドセーフではないことについて、明確にドキュメントに記述してください。

constをどこに置くか

Some people favor the form int const *foo to const int* foo. 人によっては、const int* fooの形よりint const *fooの形を推す人もいます。 They argue that this is more readable because it's more consistent: it keeps the rule that const always follows the object it's describing. 彼らの主張は「そちらの方が、常にconstがオブジェクトの後に続くというルールを一貫して保てるため、可読性が高い」というものです。 However, this consistency argument doesn't apply in codebases with few deeply-nested pointer expressions since most const expressions have only one const, and it applies to the underlying value. しかし、この一貫性に関する主張は、多重ネストされたポインタ式がほとんど出現しないコードベースにおいては、あまり当てはまりません。 ほとんどのconstの式において、constは1度だけ表れ、かつ、そのconstはポインタが指し示す先の値に対して適用されることが多いためです。 In such cases, there's no consistency to maintain. このような場合、そもそも、維持すべき一貫性そのものが存在しなくなります。 Putting the const first is arguably more readable, since it follows English in putting the "adjective" (const) before the "noun" (int). 一方で、constを前置する形(const int)は、英文法の語順のように、形容詞constの後に名詞intが続くため、おそらく、多くの人にとって読みやすいと感じられるはずです。

That said, while we encourage putting const first, we do not require it. 以上より、constを前置する形を推奨としますが、これを必須のルールとはしません。 But be consistent with the code around you! ただし、常に周囲のコードとの一貫性は保つようにしてください。

constexpr, constinit, constevalの使い方

Use constexpr to define true constants or to ensure constant initialization. 真の定数を宣言したいとき、あるいは、定数初期化を保証したいときには、constexprを使います。 Use constinit to ensure constant initialization for non-constant variables. 非定数変数に対する定数初期化を保証したいときは、constinitを使います。

Some variables can be declared constexpr to indicate the variables are true constants, i.e., fixed at compilation/link time. 変数宣言においてconstexprをつけることで、それらが真の定数(すなわち、コンパイル時かリンク時に確定する不変の値)であることを示すことができます。 Some functions and constructors can be declared constexpr which enables them to be used in defining a constexpr variable. 関数やコンストラクタの宣言においてconstexprをつけると、それらはconstexpr変数の定義のためにも用いることができるようになります。 Functions can be declared consteval to restrict their use to compile time. 関数宣言においてconstevalをつけると、それらの関数をコンパイル時にのみ評価できる(呼び出せる)ように制限することができます。

Use of constexpr enables definition of constants with floating-point expressions rather than just literals; definition of constants of user-defined types; and definition of constants with function calls. constexprを用いると、単なるリテラルでない浮動小数点の式による定数や、ユーザー定義の型の定数、あるいは、関数呼び出しを伴う定数を宣言することができます。

Prematurely marking something as constexpr may cause migration problems if later on it has to be downgraded. 早まったconstexpr宣言は、後にダウングレードの必要が生じた際に、作業の妨げとなるかもしれません。 Current restrictions on what is allowed in constexpr functions and constructors may invite obscure workarounds in these definitions. また、現時点のconstexpr関数・コンストラクタにはできることに制限があるため、それらの制限を迂回する目的だけのために、回りくどいコーディング手法を引き込んでしまうかもしれません。

constexpr definitions enable a more robust specification of the constant parts of an interface. constexprを用いると、インターフェースにおける不変部分の仕様をより堅牢にすることができます。 Use constexpr to specify true constants and the functions that support their definitions. 真の定数や、それらの定義に用いる関数を定義するためには、constexprを使ってください。 consteval may be used for code that must not be invoked at runtime. 実行時に呼び出されてはならないコードのためには、constevalを使ってもかまいません。 Avoid complexifying function definitions to enable their use with constexpr. ただし、関数をconstexprに対して適格にする目的のためだけにコードを複雑化させることは避けてください。 Do not use constexpr or consteval to force inlining. また、インライン化を強制する目的ではconstexprconstevalを使ってはいけません。

整数型

Of the built-in C++ integer types, the only one used is int. C++の組み込みの整数型の中では、使ってよいのはintだけです。 If a program needs an integer type of a different size, use an exact-width integer type from <cstdint>, such as int16_t. プログラムで異なるサイズの整数型を必要とするときは、<cstdint>から、int16_tのような、サイズが厳密に定められている整数型を使ってください。 If you have a value that could ever be greater than or equal to 2^31, use a 64-bit type such as int64_t. 値が2³¹以上になりうる変数には、int64_tのような64ビット型を使ってください。 Keep in mind that even if your value won't ever be too large for an int, it may be used in intermediate calculations which may require a larger type. また、計算結果の値がintの範囲内に収まるとわかっていても、その計算過程で一時的に大きな型を必要とする場合がありますので、この点には常に十分注意してください。 When in doubt, choose a larger type. 迷ったときには、より大きい型を選びましょう。

C++ does not specify exact sizes for the integer types like int. C++の仕様では、int等の組み込みの整数型のサイズが定めてられていません。 Common sizes on contemporary architectures are 16 bits for short, 32 bits for int, 32 or 64 bits for long, and 64 bits for long long, but different platforms make different choices, in particular for long. 現代的なアーキテクチャにおいては、shortは16ビット、intは32ビット、longは32ビットか64ビット、long longは64ビットという環境が一般的ですが、これらの整数型のサイズはプラットフォームごとに異なっており、特にlongには注意が必要です。

Uniformity of declaration. 画一的な宣言を用いることができます。

The sizes of integral types in C++ can vary based on compiler and architecture. C++の組み込み整数型のサイズは、コンパイラとアーキテクチャによって様々に異なります。

The standard library header <cstdint> defines types like int16_t, uint32_t, int64_t, etc. 標準ライブラリヘッダーの<cstdint>によって、int16_tuint32_tint64_tなどの型が定義されています。 You should always use those in preference to short, unsigned long long and the like, when you need a guarantee on the size of an integer. 整数型のサイズを保証する必要があるときは、shortunsigned long longなどの組み込み型ではなく、常にサイズの明示された型を使ってください。 Prefer to omit the std:: prefix for these types, as the extra 5 characters do not merit the added clutter. また、これらの型については、std::を省略する方が望ましいです。この余分な5文字は、その乱雑さに見合うメリットがありません。 Of the built-in integer types, only int should be used. 組み込みの整数型については、intのみを使います。 When appropriate, you are welcome to use standard type aliases like size_t and ptrdiff_t. また、適切な場合はsize_tptrdiff_tなどの標準の型エイリアスを使うことも、もちろん問題ありません。

We use int very often, for integers we know are not going to be too big, e.g., loop counters. intは非常によく使われます。たとえばループカウンタなど、そこまで大きくならないとわかっている整数については、 Use plain old int for such things. 普通のintを使ってください。 You should assume that an int is at least 32 bits, but don't assume that it has more than 32 bits. intは最低でも32ビット以上あると考えてかまいませんが、32ビットよりも大きいと考えてはいけません。 If you need a 64-bit integer type, use int64_t or uint64_t. 64ビットの整数型が必要なときは、int64_tuint64_tを使ってください。

For integers we know can be "big", use int64_t. 整数が大きくなるかもしれないときはint64_tを使ってください。

You should not use the unsigned integer types such as uint32_t, unless there is a valid reason such as representing a bit pattern rather than a number, or you need defined overflow modulo 2^N. unsignedの整数型(uint32_t等)は、何らか正当な理由がなければ使ってはいけません。これには、たとえば、変数が数値ではなくビットパターンを表しているときや、あるいは、2^Nでの剰余によるオーバーフロー時の動作を定義したいときなどが当てはまります。 In particular, do not use unsigned types to say a number will never be negative. 一方で、特に、整数が決して負にならないことを表明する目的ではunsigned型を使ってはいけません。 Instead, use assertions for this. この用途には、かわりにアサーションを使ってください。

If your code is a container that returns a size, be sure to use a type that will accommodate any possible usage of your container. 何らかのコンテナ型を作るときは、そのサイズを返すための型として、そのコンテナ型がどのような(適正な)使われ方をしたとしても対応可能な型を選んでください。 When in doubt, use a larger type rather than a smaller type. 迷ったときは、より大きな型を選びましょう。

Use care when converting integer types. 整数型の変換には注意してください。 Integer conversions and promotions can cause undefined behavior, leading to security bugs and other problems. 整数型の変換や拡張は、ときに未定義動作を引き起こし、セキュリティ上のバグやその他の問題に繋がることがあります。

unsigned整数型について

Unsigned integers are good for representing bitfields and modular arithmetic. unsigned整数型は、ビットフィールドや剰余演算に有用です。 Because of historical accident, the C++ standard also uses unsigned integers to represent the size of containers - many members of the standards body believe this to be a mistake, but it is effectively impossible to fix at this point. 歴史的な事情により、C++標準では、コンテナのサイズを表すためにunsigned整数型が使われており、この点について多くのC++標準化委員会のメンバーがこれを失敗だったと考えていますが、現在において、もはや修正は不可能となってしまいました。 The fact that unsigned arithmetic doesn't model the behavior of a simple integer, but is instead defined by the standard to model modular arithmetic (wrapping around on overflow/underflow), means that a significant class of bugs cannot be diagnosed by the compiler. 標準によって定義されるunsigned整数演算は、単純な整数演算の挙動をモデル化したものではなく、オーバーフロー時に値が周回する、合同算術をモデル化したものです。 このことは、これに起因する様々なバグについて、コンパイラが診断できないということを意味します。 In other cases, the defined behavior impedes optimization. また、このような挙動の定義のために、コンパイラによる最適化が妨げられることもあります。

That said, mixing signedness of integer types is responsible for an equally large class of problems. とはいえ、signed整数型とunsigned整数型を混在させてしまうと、それもまた同様に様々なバグの要因となります。 The best advice we can provide: try to use iterators and containers rather than pointers and sizes, try not to mix signedness, and try to avoid unsigned types (except for representing bitfields or modular arithmetic). ここでの最大限のアドバイスとしては、「コンテナについては、ポインタやサイズではなく、イテレータを使う」「signed整数型とunsigned整数型が混在しないようにする」「(ビットフィールドや合同演算を目的としない限り) そもそも、unsigned整数型を使うのを避ける」というところです。 Do not use an unsigned type merely to assert that a variable is non-negative. 変数が常に非負であることを主張する目的程度のことでは、unsigned整数型を使ってはいけません。

64ビットへの移植性

Code should be 64-bit and 32-bit friendly. コードは64ビット環境と32ビット環境の両方にフレンドリーであるべきです。 Bear in mind problems of printing, comparisons, and structure alignment. printf等で出力するときの問題、値を比較するときの問題、構造体のアライメントの問題を常に心にとめておいてください。

プリプロセッサマクロ

Avoid defining macros, especially in headers; prefer inline functions, enums, and const variables. マクロを定義しないでください。 特にヘッダーではマクロを定義しないでください。 かわりに、インライン関数や、列挙型、const変数を用いましょう。 Name macros with a project-specific prefix. マクロの名前にはプロジェクト固有の接頭辞(接頭辞)をつけます。 Do not use macros to define pieces of a C++ API. C++ APIの定義としてマクロを使ってはいけません。

Macros mean that the code you see is not the same as the code the compiler sees. マクロを使うということは、あなたが見ているコードと、コンパイラが見ているコードとが同じではなくなるということを意味します。 This can introduce unexpected behavior, especially since macros have global scope. 特にマクロはグローバルスコープを持つため、それによって、予期せぬ挙動を招くことがあります。

The problems introduced by macros are especially severe when they are used to define pieces of a C++ API, and still more so for public APIs. マクロによって引き起こされる問題は、特にマクロがC++のAPIの一部として定義されたとき、加えて、それらが公開APIであるときは殊更、深刻なものとなる場合があります。 Every error message from the compiler when developers incorrectly use that interface now must explain how the macros formed the interface. 開発者がインターフェースを誤って使用したときに生成されるコンパイルエラーメッセージにおいて、それらのマクロがインターフェースをどのように形成しているのか説明していなければなりません。 Refactoring and analysis tools have a dramatically harder time updating the interface. また、マクロを使うと、リファクタリングツールや解析ツールがインターフェースを更新するときに、劇的な時間が掛かるようにもなります。 As a consequence, we specifically disallow using macros in this way. 結論として、この用途でのマクロは明確に禁止とします。 For example, avoid patterns like: 例として、次のようなパターンは避けてください。

class WOMBAT_TYPE(Foo) {
  // ...

 public:
  EXPAND_PUBLIC_WOMBAT_API(Foo)

  EXPAND_WOMBAT_COMPARISONS(Foo, ==, <)
};

Luckily, macros are not nearly as necessary in C++ as they are in C. 幸いなことに、C++ではC言語に比べてほとんどマクロを必要としません。 Instead of using a macro to inline performance-critical code, use an inline function. パフォーマンスクリティカルなコードをインライン化する目的では、マクロではなく、インライン関数を使うことができます。 Instead of using a macro to store a constant, use a const variable. 定数を保持するためには、マクロではなく、const変数を使うことができます。 Instead of using a macro to "abbreviate" a long variable name, use a reference. 長い名前の変数への省略形を作るためには、マクロではなく、参照を使うことができます。 Instead of using a macro to conditionally compile code ... well, don't do that at all (except, of course, for the #define guards to prevent double inclusion of header files). 条件によってコンパイルされるコードを変えるためには、マクロではなく……いや、そもそも、そのようなことはしないでください(もちろん、ヘッダファイルにおけるインクルードガードは例外です)。 It makes testing much more difficult. そのようなことをすると、テストが非常に難しくなります。

Macros can do things these other techniques cannot, and you do see them in the codebase, especially in the lower-level libraries. マクロを使うと、他の手段では不可能なことが実現できます。 コードベースの中でも、特に低レベルライブラリにおいて、それらを見かけることがあるかもしれません。 And some of their special features (like stringifying, concatenation, and so forth) are not available through the language proper. たとえば、マクロには、シンボルの文字列化や連結といった特殊な機能があり、これらは言語系では提供されていません。 But before using a macro, consider carefully whether there's a non-macro way to achieve the same result. それでも、マクロを使う前に、それ以外の方法で同様の結果を得ることができないか、よく検討するようにしてください。 If you need to use a macro to define an interface, contact your project leads to request a waiver of this rule. どうしてもマクロを使ってインターフェースを定義しなければならないときには、このルールの放棄について、プロジェクトリーダーと相談してください。

The following usage pattern will avoid many problems with macros; if you use macros, follow it whenever possible: 以下に示すパターンに従うと、マクロにまつわる多くの問題を避けることができます。もし、マクロを使うのであれば、可能な限りこれらに従ってください。

Exporting macros from headers (i.e., defining them in a header without #undefing them before the end of the header) is extremely strongly discouraged. ヘッダーからマクロをエクスポートすること(すなわち、ヘッダーでマクロを定義し、そのまま#undefしないこと)は、まったく非常に強く非推奨です。 If you do export a macro from a header, it must have a globally unique name. どうしても、ヘッダーからマクロをエクスポートする場合は、必ずグローバルにユニークな名前をつけてください。 To achieve this, it must be named with a prefix consisting of your project's namespace name (but upper case). このことを達成するために、マクロの名前には、そのプロジェクトの名前空間の名前をすべて大文字にして接頭辞としてつけるようにしてください。

0nullptrNULL

Use nullptr for pointers, and '\0' for chars (and not the 0 literal). ポインタにはnullptr、文字には'\0'を使います。これらの目的でリテラルの0は使いません。

For pointers (address values), use nullptr, as this provides type-safety. ポインタ(アドレス値)には、nullptrを使ってください。nullptrを使えば型安全になります。

Use '\0' for the null character. ヌル文字には'\0'を使ってください。 Using the correct type makes the code more readable. 正しい型のリテラルを用いることで、コードがより読みやすくなります。

sizeof

Prefer sizeof(varname) to sizeof(type). sizeof()よりもsizeof(変数名)の形を優先的に使いましょう。

Use sizeof(varname) when you take the size of a particular variable. 具体的な変数のサイズを知りたいときにはsizeof(変数名)とします。 sizeof(varname) will update appropriately if someone changes the variable type either now or later. sizeof(変数名)の形を使っていれば、将来、変数の型が変更される場合にも、適切に追従することができます。 You may use sizeof(type) for code unrelated to any particular variable, such as code that manages an external or internal data format where a variable of an appropriate C++ type is not convenient. 一方で、コードが具体的な変数に結びつかないときにはsizeof()の形を使ってもかまいません。 たとえば、以下の例のように、外部または内部のデータフォーマットそのものを扱っていて、わざわざ適切なC++の型の変数を用意するのでは不便な場合です。

MyStruct data;
memset(&data, 0, sizeof(data));
memset(&data, 0, sizeof(MyStruct));
memset(&data, 0, sizeof(MyStruct));  // これは避ける
if (raw_size < sizeof(int)) {
  LOG(ERROR) << "compressed record not big enough for count: " << raw_size;
  return false;
}

型推論(autoを含む)

Use type deduction only if it makes the code clearer to readers who aren't familiar with the project, or if it makes the code safer. 型推論は、型推論によって、そのプロジェクトに馴染みのないコード読者にとっても、コードが読みやすくなることを期待できる場合や、あるいは、型推論によってコードをより安全にできる場合に限って使用します。 Do not use it merely to avoid the inconvenience of writing an explicit type. 明示的に型を記述するのが面倒だからという理由では、型推論を使ってはいけません。

There are several contexts in which C++ allows (or even requires) types to be deduced by the compiler, rather than spelled out explicitly in the code: C++では、いくつかの文脈において、型を明示するかわりに、コンパイラによる推論を許す(あるいは、そうしなければならない)ことがあります。

Function template argument deduction 関数テンプレートの実引数推論
A function template can be invoked without explicit template arguments. 関数テンプレートは、明示的にテンプレート引数を与えずとも呼び出すことができます。 The compiler deduces those arguments from the types of the function arguments: コンパイラは、実際に関数に渡された引数の型から、これらのテンプレート引数を推論します。
template <typename T>
void f(T t);

f(0);  // Invokes f<int>(0)
template <typename T>
void f(T t);
    
f(0);  // f<int>(0) を呼び出す
auto variable declarations auto変数宣言
A variable declaration can use the auto keyword in place of the type. 変数宣言では、型のかわりにautoキーワードを使うことができます。 The compiler deduces the type from the variable's initializer, following the same rules as function template argument deduction with the same initializer (so long as you don't use curly braces instead of parentheses). コンパイラは、変数の初期化子から、関数テンプレートの実引数推論と同じ規則に従い、変数の型を推論します(丸括弧のかわりに波括弧を使用しない限り)。
auto a = 42;  // a is an int
auto& b = a;  // b is an int&
auto c = b;   // c is an int
auto d{42};   // d is an int, not a std::initializer_list<int>
auto a = 42;  // a は int型
auto& b = a;  // b は int&型
auto c = b;   // c は int型
auto d{42};   // d は int型 ※ std::initializer_list<int>ではない
auto can be qualified with const, and can be used as part of a pointer or reference type, but it can't be used as a template argument. autoconstで修飾することができ、また、ポインタまたは参照型の一部分として用いることもできますが、テンプレート実引数に用いることはできません。 A rare variant of this syntax uses decltype(auto) instead of auto, in which case the deduced type is the result of applying decltype to the initializer. また、この文法のまれに見る変種として、autoのかわりにdecltype(auto)というものもあります。 decltype(auto)を使った場合は、初期化子をdecltypeに渡したときに行われる型推論と同じ規則に従って、その結果の型に解決されることになります。
Function return type deduction 関数戻り値の型推論
auto (and decltype(auto)) can also be used in place of a function return type. auto (とdecltype(auto))は、関数の戻り値の型として用いることもできます。 The compiler deduces the return type from the return statements in the function body, following the same rules as for variable declarations: コンパイラは、関数本体のreturn文から、変数宣言のときと同じ規則に従って、戻り値の型を推論します。
auto f() { return 0; }  // The return type of f is int
auto f() { return 0; }  // f の戻り値の型は int
Lambda expression return types can be deduced in the same way, but this is triggered by omitting the return type, rather than by an explicit auto. また、ラムダ式の戻り値の型も同じ方法で推論させることができますが、ラムダ式の場合は、明示的なautoではなく、単に戻り値の型を省略したときに型推論が行われます。 Confusingly, trailing return type syntax for functions also uses auto in the return-type position, but that doesn't rely on type deduction; it's just an alternate syntax for an explicit return type. なお、紛らわしいことに、関数宣言の末尾に戻り値の型を書く構文においてもautoキーワードが表れますが、このautoは型推論とは関係がありません。この構文は、戻り値の型が明示された別の形の構文にすぎず、型推論は行われません。
Generic lambdas ジェネリックラムダ
A lambda expression can use the auto keyword in place of one or more of its parameter types. ラムダ式では、仮引数の型としてautoキーワードを用いることができます。 This causes the lambda's call operator to be a function template instead of an ordinary function, with a separate template parameter for each auto function parameter: 1つ以上のauto仮引数を宣言すると、その関数呼び出し演算子(operator())が通常の関数ではなく関数テンプレートとなり、 各auto仮引数ごとに個別のテンプレート引数が割り当てられます。
// Sort `vec` in decreasing order
std::sort(vec.begin(), vec.end(), [](auto lhs, auto rhs) { return lhs > rhs; });
// `vec` を降順ソート
std::sort(vec.begin(), vec.end(), [](auto lhs, auto rhs) { return lhs > rhs; });
Lambda init captures ラムダの初期化キャプチャ
Lambda captures can have explicit initializers, which can be used to declare wholly new variables rather than only capturing existing ones: ラムダのキャプチャでは、既存変数をキャプチャできるだけではなく、明示的な初期化子を与えることで、まったく新しい変数を宣言することもできます。
[x = 42, y = "foo"] { ...
}  // x is an int, and y is a const char*
[x = 42, y = "foo"] { ...
}  // x は int で、y は const char*
This syntax doesn't allow the type to be specified; instead, it's deduced using the rules for auto variables. この構文において、変数の型を明示的に指定する方法はありません。かわりにauto変数宣言時のルールに従って型推論が行われます。
Class template argument deduction クラス テンプレートの引数推論
See below. これについては、後述します
Structured bindings 構造化束縛
When declaring a tuple, struct, or array using auto, you can specify names for the individual elements instead of a name for the whole object; these names are called "structured bindings", and the whole declaration is called a "structured binding declaration". autoを使ってタプルや構造体や配列を宣言するとき、オブジェクト全体に名前を付けるかわりに、個々の要素に名前を付けることもできます。 これらの名前のことを「構造化束縛(structured binding)」と呼び、その宣言全体を「構造化束縛宣言(structured binding declaration)」と呼びます。 This syntax provides no way of specifying the type of either the enclosing object or the individual names: この構文においては、全体を囲むオブジェクトの型も、個々の要素の型も、いずれも明示的に指定する方法はありません。
auto [iter, success] = my_map.insert({key, value});
if (!success) {
    iter->second = value;
}
The auto can also be qualified with const, &, and &&, but note that these qualifiers technically apply to the anonymous tuple/struct/array, rather than the individual bindings. このautoは、const&、および &&で修飾することもできます。ただし、これらの修飾子は、技術的には、個々の要素に対してではなく、その宣言で作られる無名のタプルや構造体、配列そのものに適用されていることに注意してください。 The rules that determine the types of the bindings are quite complex; the results tend to be unsurprising, except that the binding types typically won't be references even if the declaration declares a reference (but they will usually behave like references anyway). これらの束縛変数の型を決定するルールはかなり複雑です。 結果的には、概ね想像通りの挙動にはなるのですが、構造化束縛宣言全体が参照である場合であっても、各々の束縛変数の型が参照型になるわけではないため、この点には注意が必要です(ただし、いずれにせよ、それらは参照であるかのように振る舞います)。

(These summaries omit many details and caveats; see the links for further information.) (ここまでの要約においては、多くの詳細と注釈すべき事項が割愛されています。より詳しい知識を得るべく、各リンク先も参照するようにしてください)

C++ code is usually clearer when types are explicit, especially when type deduction would depend on information from distant parts of the code. C++のコードは、通常は、型が明示されている方が明確でわかりやすいものになります。 特に、型推論のために必要な情報が、コードの離れた場所に位置していると、コードを理解しにくくなることがあります。 In expressions like: 次のような例を考えてみましょう。

auto foo = x.add_foo();
auto i = y.Find(key);

it may not be obvious what the resulting types are if the type of y isn't very well known, or if y was declared many lines earlier. このコードにおいて、yの型が十分有名でなかったり、あるいは、yが何十行も前に宣言されていたりすると、結果の型が何であるかは明確でなくなります。

Programmers have to understand when type deduction will or won't produce a reference type, or they'll get copies when they didn't mean to. また、プログラマーは、型推論によってどの場合に参照型が生成され、どの場合に通常の型が生成されるのか、しっかり理解していなければなりません。さもなくば、意図せずオブジェクトをコピーしてしまうことになるでしょう。

If a deduced type is used as part of an interface, then a programmer might change its type while only intending to change its value, leading to a more radical API change than intended. 型推論がインターフェースの一部として使われてしまっている場合、プログラマーはその値だけを変えるつもりで、うっかり、型をも変えてしまうかもしれません。これによって、本来意図したよりも大きなAPIの変更を招いてしまうかもしれません。

The fundamental rule is: use type deduction only to make the code clearer or safer, and do not use it merely to avoid the inconvenience of writing an explicit type. 基本的なルールとして、型推論は、型推論によってコードが明確になる、もしくは、安全になるときに限って使用するようにしてください。型を明示的に記述するのが面倒だ、という理由で型推論を使ってはいけません。 When judging whether the code is clearer, keep in mind that your readers are not necessarily on your team, or familiar with your project, so types that you and your reviewer experience as unnecessary clutter will very often provide useful information to others. コードが明確であるかどうかの判定基準を考えるときには、そのコードの読者として、プロジェクトチーム外のプロジェクトに詳しくない人を想定してください。 コードの著者やレビュアーにとって無用に散らかっているように感じられる細かい型の記述であっても、それ以外の人たちにとっては有益な情報源の役割を果たしているということは、実際によくあることです。 For example, you can assume that the return type of make_unique<Foo>() is obvious, but the return type of MyWidgetFactory() probably isn't. たとえば、std::make_unique<Foo>()の戻り値の型は誰が見ても明確であると言えますが、MyWidgetFactory()の戻り値の型は、おそらくそうではありません。

These principles apply to all forms of type deduction, but the details vary, as described in the following sections. これらの原則は、すべての形の型推論に当てはまります。ただし、細かいところで異なる点もあるため、それらについて以降のセクションで詳しく説明します。

関数テンプレートの引数推論

Function template argument deduction is almost always OK. 関数テンプレート引数の型推論は、ほとんどの場合において問題ありません。 Type deduction is the expected default way of interacting with function templates, because it allows function templates to act like infinite sets of ordinary function overloads. 関数テンプレートにおいては、型推論を用いることがむしろ通常の使用方法として想定されており、それによって、関数テンプレートが無限のオーバーロードを持つ関数集合であるかのように振る舞えます。 Consequently, function templates are almost always designed so that template argument deduction is clear and safe, or doesn't compile. したがって、関数テンプレートは、ほとんど常に、そのテンプレート引数を明確かつ安全に推論できるか、さもなくばコンパイルエラーになるように設計されています。

ローカル変数の型推論

For local variables, you can use type deduction to make the code clearer by eliminating type information that is obvious or irrelevant, so that the reader can focus on the meaningful parts of the code: ローカル変数については、型推論によって、明白あるいは不適切な型に関する情報を省き、コードをより明確にできる場合があります。 そうすることで、コード読者がコードの本質的な部分に集中できるようになります。次の2つの例を見比べてみてください。

std::unique_ptr<WidgetWithBellsAndWhistles> widget =
    std::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2);
absl::flat_hash_map<std::string,
                    std::unique_ptr<WidgetWithBellsAndWhistles>>::const_iterator
    it = my_map_.find(key);
std::array<int, 6> numbers = {4, 8, 15, 16, 23, 42};
auto widget = std::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2);
auto it = my_map_.find(key);
std::array numbers = {4, 8, 15, 16, 23, 42};

Types sometimes contain a mixture of useful information and boilerplate, such as it in the example above: it's obvious that the type is an iterator, and in many contexts the container type and even the key type aren't relevant, but the type of the values is probably useful. 型には、上述の例におけるitのように、有益な情報とただの定型コードとの両方が混在していることがあります。 itがイテレータ型であることは明白ですし、多くの文脈においてはコンテナの型やキーの型さえも不要な情報でしょう。それでも、値の型に関する情報は依然として有益である場合があります。 In such situations, it's often possible to define local variables with explicit types that convey the relevant information: このような状況では、大抵の場合、以下の例のように、型を明示したローカル変数を定義することで、関連する情報を伝えることができます。

if (auto it = my_map_.find(key); it != my_map_.end()) {
    WidgetWithBellsAndWhistles& widget = *it->second;
    // Do stuff with `widget`
}
if (auto it = my_map_.find(key); it != my_map_.end()) {
    WidgetWithBellsAndWhistles& widget = *it->second;
    // `widget`に関する操作を行う
}

If the type is a template instance, and the parameters are boilerplate but the template itself is informative, you can use class template argument deduction to suppress the boilerplate. 型がテンプレートインスタンスであって、そのテンプレート引数はただの定型文であるが、それでもテンプレート自体の名前には有益な情報を含む、という場合には、クラステンプレートの実引数推論を利用することで、定型の部分を省略することができる場合があります。 However, cases where this actually provides a meaningful benefit are quite rare. ただし、これらが実際に意味のある利益をもたらす機会はほとんどありません。 Note that class template argument deduction is also subject to a separate style rule. なお、クラステンプレートの実引数推論を行う場合は、それ専用のスタイルルールにも従う必要がありますので、意してください。

Do not use decltype(auto) if a simpler option will work, because it's a fairly obscure feature, so it has a high cost in code clarity. decltype(auto)について、より単純な手段で十分な場合には、わざわざdecltype(auto)を使ってはいけません。decltype(auto)は、かなり難しい機能であるため、コードの明確さの面で大きなコストとなってしまうためです。

戻り値の型推論

Use return type deduction (for both functions and lambdas) only if the function body has a very small number of return statements, and very little other code, because otherwise the reader may not be able to tell at a glance what the return type is. 戻り値の型推論を使用するのは、通常の関数とラムダ式のいずれの場合でも、関数本体に含まれるreturn文の数が非常に少なく、かつ、その他のコードがほとんどない場合に限定してください。コードの読者が、その関数を一目見ただけで戻り値の型を判断できないような場合には、戻り値の型推論を使わないでください。 Furthermore, use it only if the function or lambda has a very narrow scope, because functions with deduced return types don't define abstraction boundaries: the implementation is the interface. さらに言えば、戻り値の型を推論に委ねる関数は、抽象化の境界を定義せず、その実装そのものがそのままインターフェースとなるため、それらの関数やラムダが非常に狭いスコープから使われる場合のみに限定される方が望ましいです。 In particular, public functions in header files should almost never have deduced return types. 特に、ヘッダーファイルにて公開される関数では、戻り値の型の推論は、ほとんど、まったく、用いるべきではありません。

引数の型推論

auto parameter types for lambdas should be used with caution, because the actual type is determined by the code that calls the lambda, rather than by the definition of the lambda. ラムダ式の引数をautoにするときは注意が必要です。 これは、引数の実際の型が、ラムダの定義ではなく、ラムダを呼び出すコードによって決定されるためです。 Consequently, an explicit type will almost always be clearer unless the lambda is explicitly called very close to where it's defined (so that the reader can easily see both), or the lambda is passed to an interface so well-known that it's obvious what arguments it will eventually be called with (e.g., the std::sort example above). したがって、ラムダの定義とその呼び出しがすぐ近くにあって両者のコードを容易に見つけられる場合や、あるいは、ラムダが非常によく知られたインターフェース(std::sortなど)に渡されていて、呼び出し時の実引数の型を容易に想像できる場合などを除けば、それ以外は、ほとんど常に、ラムダの引数の型を明示する方がコードがわかりやすくなります。

ラムダ式の初期化キャプチャ

Init captures are covered by a more specific style rule, which largely supersedes the general rules for type deduction. 初期化キャプチャに関しては、より具体的なスタイルルールによってカバーします。これは、型推論の一般的なルールに大きく取って代わるものです。

構造化束縛

Unlike other forms of type deduction, structured bindings can actually give the reader additional information, by giving meaningful names to the elements of a larger object. 他の形式の型推論とは異なり、構造化束縛では、大きなオブジェクトの各要素に意味のある名前を付けられるため、コード読者に付加的な情報を提供することができます。 This means that a structured binding declaration may provide a net readability improvement over an explicit type, even in cases where auto would not. これは、そのauto自体が可読性の向上に貢献しないとしても、型を明示的に書くよりも構造化束縛宣言を用いる方が、全体としての可読性が高まることがある、ということを意味します。 Structured bindings are especially beneficial when the object is a pair or tuple (as in the insert example above), because they don't have meaningful field names to begin with, but note that you generally shouldn't use pairs or tuples unless a pre-existing API like insert forces you to. 構造化束縛が特に真価を発揮するのは、(上記例のinsertのように、)、ペアやタプルのような、フィールド名に意味を持たない型を扱う場合です。 (ただし、insertなどの既存のAPIによって強制される場合以外では、そもそもペアやタプルを使うべきではありません。)

If the object being bound is a struct, it may sometimes be helpful to provide names that are more specific to your usage, but keep in mind that this may also mean the names are less recognizable to your reader than the field names. 束縛対象のオブジェクトが構造体である場合、その場での各フィールドの使い方に特化した名前を付け直すことで、コードがわかりやすくなる場合もあります。 ただし、逆に、新しい名前によって元のフィールド名を見分けにくくなってしまうかもしれないことにも気をつけてください。 We recommend using a comment to indicate the name of the underlying field, if it doesn't match the name of the binding, using the same syntax as for function parameter comments: 束縛名と元のフィールド名とを変える場合は、関数引数のコメントと同じ構文で、元のフィールド名をコメントとして記述することをおすすめします。

auto [/*field_name1=*/bound_name1, /*field_name2=*/bound_name2] = ...

As with function parameter comments, this can enable tools to detect if you get the order of the fields wrong. こうすることで、フィールドの順序が間違っていないかどうかを、関数引数のコメントと同様に、ツールに検出させることができるようになるでしょう。

クラステンプレートのテンプレート引数推論(CTAD)

Use class template argument deduction only with templates that have explicitly opted into supporting it. 「クラステンプレートのテンプレート引数推論」は、それについて対応していることが明示されているテンプレートに対してのみ利用します。

Class template argument deduction (often abbreviated "CTAD") occurs when a variable is declared with a type that names a template, and the template argument list is not provided (not even empty angle brackets): クラステンプレートのテンプレート引数推論(しばしば "CTAD" と略される)は、 変数の型がテンプレート名で宣言され、かつ、その宣言でテンプレートの引数リストが与えられなかった場合(空の山括弧もない)に行われます。

std::array a = {1, 2, 3};  // `a` is a std::array<int, 3>
std::array a = {1, 2, 3};  // `a` は std::array<int, 3>

The compiler deduces the arguments from the initializer using the template's "deduction guides", which can be explicit or implicit. コンパイラは、そのテンプレートの明示的または暗黙的な「推論ガイド」を使用して、初期化子からテンプレート引数を推論します。

Explicit deduction guides look like function declarations with trailing return types, except that there's no leading auto, and the function name is the name of the template. 明示的な推論ガイドの見た目は、戻り値の型を末尾におく関数宣言のような形をしていますが、先頭にautoが置かれず、関数名の部分にテンプレート名が使われます。 For example, the above example relies on this deduction guide for std::array: たとえば、上記の例は、std::arrayの次の推論ガイドに依存しています。

namespace std {
    template <class T, class...U>
    array(T, U...) -> std::array<T, 1 + sizeof...(U)>;
}

Constructors in a primary template (as opposed to a template specialization) also implicitly define deduction guides. テンプレートの特殊化とは異なり、プライマリテンプレートのコンストラクタも、暗黙的な推論ガイドを定義します。

When you declare a variable that relies on CTAD, the compiler selects a deduction guide using the rules of constructor overload resolution, and that guide's return type becomes the type of the variable. CTADを用いた変数宣言においては、コンストラクタのオーバーロード解決の規則に沿って推論ガイドが選択され、そのガイドの戻り値の型が変数の型になります。

CTAD can sometimes allow you to omit boilerplate from your code. CTADでは、コードから定型文を省略できる場合があります。

The implicit deduction guides that are generated from constructors may have undesirable behavior, or be outright incorrect. コンストラクタから自動生成される暗黙的な推論ガイドは、望ましくない動作をしたり、あるいは、まったくもって正しくない場合があります。 This is particularly problematic for constructors written before CTAD was introduced in C++17, because the authors of those constructors had no way of knowing about (much less fixing) any problems that their constructors would cause for CTAD. これらは、特に、C++17でCTADが導入される前に書かれたコンストラクタで問題になりがちです。 これらのコンストラクタの著者は、これらのコンストラクタがCTADによって引き起こす問題について、何ら知る由もなかったでしょう。 Furthermore, adding explicit deduction guides to fix those problems might break any existing code that relies on the implicit deduction guides. さらに、これらの問題を修正するために明示的な推論ガイドを追加しようとすると、今度は、それまでの暗黙的な推論ガイドに依存している既存のコードを壊してしまう恐れさえあります。

CTAD also suffers from many of the same drawbacks as auto, because they are both mechanisms for deducing all or part of a variable's type from its initializer. CTADにもautoと同様の欠点が数多くあります。 これらの仕組みは、どちらも、その初期化子から変数の型またはその一部を推論するためのものだからです。 CTAD does give the reader more information than auto, but it also doesn't give the reader an obvious cue that information has been omitted. CTADは、autoに比べればより多くの情報を読者に提供していますが、それでも、情報が省略されていること自体を明確に伝えることはありません。

Do not use CTAD with a given template unless the template's maintainers have opted into supporting use of CTAD by providing at least one explicit deduction guide (all templates in the std namespace are also presumed to have opted in). テンプレートのメンテナンス担当者によって1つ以上の明示的な推論ガイドが提供されている場合、そのテンプレートは明示的にCTADに対応していると見なすことができます。CTADは、この場合に限り利用するものとし、それ以外の場合はCTADを避けてください (なお、std名前空間のテンプレートについては、それらのすべてがCTADに対応していると見なしてかまいません)。 This should be enforced with a compiler warning if available. これついて、可能であればコンパイラの警告を有効にすることで、強制されるようにしてください。

Uses of CTAD must also follow the general rules on Type deduction. なお、CTADは型推論に関する一般的なルールにも従う必要がありますので、注意してください。

指示付き初期化子

Use designated initializers only in their C++20-compliant form. 指示付き初期化子は、C++20標準に準拠する形式でのみ使用します。

Designated initializers are a syntax that allows for initializing an aggregate ("plain old struct") by naming its fields explicitly: 指示付き初期化子は、各フィールド名を明示しながら集約型(aggregate) (あるいは、POD: Plain Old Structとも) を初期化できる構文です。

  struct Point {
        float x = 0.0;
        float y = 0.0;
        float z = 0.0;
      };
    
      Point p = {
        .x = 1.0,
        .y = 2.0,
        // z will be 0.0
      };

The explicitly listed fields will be initialized as specified, and others will be initialized in the same way they would be in a traditional aggregate initialization expression like Point{1.0, 2.0}. 明示的にリストアップされたフィールドは指定のとおりに初期化され、それ以外のフィールドは従来の集約初期化式(Point{1.0, 2.0})と同様に初期化されます。

Designated initializers can make for convenient and highly readable aggregate expressions, especially for structs with less straightforward ordering of fields than the Point example above. 指示付き初期化子は、特に上記の Point の例よりもフィールドの順序付けが複雑な構造体において、便利で非常に読みやすい集約式(aggregate expression)を作成できます。

While designated initializers have long been part of the C standard and supported by C++ compilers as an extension, they were not supported by C++ prior to C++20. 指示付き初期化子の機能は、長い間、標準C言語の一部であり、各C++コンパイラによる拡張機能としてもサポートされていましたが、C++20よりも前のC++ではサポートされていませんでした。

The rules in the C++ standard are stricter than in C and compiler extensions, requiring that the designated initializers appear in the same order as the fields appear in the struct definition. C++標準における規則は、標準C言語やコンパイラの拡張機能のものよりも厳しく、指示付き初期化子が、構造体の定義におけるフィールドと同じ順序で現れることを要求しています。 So in the example above, it is legal according to C++20 to initialize x and then z, but not y and then x. つまり、前述の例において、C++20に従うと、xのあとにzを初期化することは妥当ですが、yのあとにxを初期化することはできません。

Use designated initializers only in the form that is compatible with the C++20 standard: with initializers in the same order as the corresponding fields appear in the struct definition. 指示付き初期化子は、C++20標準と互換性のある形式でのみ利用してください。 すなわち、対応するフィールドが構造体定義に現れるのと同じ順序で初期化子を記述するようにしてください。

ラムダ式

Use lambda expressions where appropriate. ラムダ式は適切に使います。 Prefer explicit captures when the lambda will escape the current scope. ラムダが現在のスコープから外に出て行くときは、変数キャプチャを明示的に行いましょう。

Lambda expressions are a concise way of creating anonymous function objects. ラムダ式は匿名関数オブジェクトを作るための簡潔な手段です。 They're often useful when passing functions as arguments. For example: これらは関数の引数として渡す場合にも有用です。

std::sort(v.begin(), v.end(), [](int x, int y) {
  return Weight(x) < Weight(y);
});

They further allow capturing variables from the enclosing scope either explicitly by name, or implicitly using a default capture. さらに、ラムダ式では自身を囲むスコープから変数をキャプチャすることができます。 変数のキャプチャは、明示的に名前を指定するか、暗黙的なデフォルトのキャプチャを使うかのいずれかによって行われます。 Explicit captures require each variable to be listed, as either a value or reference capture: 明示的なキャプチャを行う場合は、次のように、各変数を値キャプチャとするか参照キャプチャとするかを指定しながらリストに並べます。

int weight = 3;
int sum = 0;
// Captures `weight` by value and `sum` by reference.
std::for_each(v.begin(), v.end(), [weight, &sum](int x) {
  sum += weight * x;
});
int weight = 3;
int sum = 0;
// weigthは値として、sumは参照としてキャプチャします。
std::for_each(v.begin(), v.end(), [weight, &sum](int x) {
  sum += weight * x;
});

Default captures implicitly capture any variable referenced in the lambda body, including this if any members are used: デフォルトキャプチャは暗黙的にラムダの本体で参照されたすべての変数をキャプチャします。何らかのメンバ変数やメンバ関数などが使われている場合はthisもキャプチャされます。

const std::vector<int> lookup_table = ...;
std::vector<int> indices = ...;
// Captures `lookup_table` by reference, sorts `indices` by the value
// of the associated element in `lookup_table`.
std::sort(indices.begin(), indices.end(), [&](int a, int b) {
  return lookup_table[a] < lookup_table[b];
});
const std::vector<int> lookup_table = ...;
std::vector<int> indices = ...;
// lookup_tableを参照としてキャプチャし、
// lookup_tableの要素に関連づけられたindicesの値をソートしています。
std::sort(indices.begin(), indices.end(), [&](int a, int b) {
  return lookup_table[a] < lookup_table[b];
});

A variable capture can also have an explicit initializer, which can be used for capturing move-only variables by value, or for other situations not handled by ordinary reference or value captures: 変数のキャプチャには、明示的な初期化子を与えることもできます。 これによって、ムーブのみ可能な型の変数を値キャプチャしたいときや、通常の参照キャプチャや値キャプチャでは対処できないその他の状況にも対応できます。

std::unique_ptr<Foo> foo = ...;
        [foo = std::move(foo)] () {
          ...
        }

Such captures (often called "init captures" or "generalized lambda captures") need not actually "capture" anything from the enclosing scope, or even have a name from the enclosing scope; this syntax is a fully general way to define members of a lambda object: このようなキャプチャ (「初期化キャプチャ」または「一般化されたラムダキャプチャ」と呼ばれる) は、実際には、それを囲むスコープから何かをキャプチャする必要はなく、囲んでいるスコープ内に名前がある必要もありません。つまり、この構文は、ラムダオブジェクトのメンバ変数を定義するための一般的な手段として用いることができます。

[foo = std::vector<int>({1, 2, 3})] () {
          ...
        }

The type of a capture with an initializer is deduced using the same rules as auto. 初期化子を使用したキャプチャの型は、autoと同じ規則によって推論されます。

テンプレートメタプログラミング

Avoid complicated template programming. 複雑なテンプレートプログラミングは避けましょう。

Template metaprogramming refers to a family of techniques that exploit the fact that the C++ template instantiation mechanism is Turing complete and can be used to perform arbitrary compile-time computation in the type domain. テンプレートメタプログラミングとは、C++のテンプレートのインスタンス化の仕組みがチューリング完全であり、コンパイル時に型の世界で任意の計算を行うことができるという事実を利用した一連のテクニックのことを指します。

Template metaprogramming allows extremely flexible interfaces that are type safe and high performance. テンプレートメタプログラミングは、型安全かつ高性能で非常に柔軟なインターフェースを提供します。 Facilities like GoogleTest, std::tuple, std::function, and Boost.Spirit would be impossible without it. GoogleTeststd::tuplestd::function、Boost.Spiritのような機能は、テンプレートメタプログラミングなしには実現できません。

The techniques used in template metaprogramming are often obscure to anyone but language experts. テンプレートメタプログラミングにおいて使われるテクニックは、言語の専門家以外にはわかりにくいものになりがちです。 Code that uses templates in complicated ways is often unreadable, and is hard to debug or maintain. 複雑な手法のテンプレートを含むコードは、可読性が低く、デバッグやメンテナンスも難しくなります。

Template metaprogramming often leads to extremely poor compile time error messages: even if an interface is simple, the complicated implementation details become visible when the user does something wrong. テンプレートメタプログラミングは、コンパイル時のエラーメッセージを非常に貧弱なものにしがちです。たとえ、インターフェースがシンプルに保たれていたとしても、ひとたびユーザーが何かを間違えた途端に、複雑な内部実装が大量のエラーメッセージとともに現れてしまうことがあります。

Template metaprogramming interferes with large scale refactoring by making the job of refactoring tools harder. テンプレートメタプログラミングは、リファクタリングツールの動作を難しくするため、大規模なリファクタリングの妨げとなることがあります。 First, the template code is expanded in multiple contexts, and it's hard to verify that the transformation makes sense in all of them. 第一に、テンプレートコードは様々な文脈で展開されますが、展開後のすべての箇所において、それらが正しい意味を持つか検証することが難しいです。 Second, some refactoring tools work with an AST that only represents the structure of the code after template expansion. 第二に、リファクタリングツールの中には、テンプレート展開のコード構造を表すASTしか扱えないものが存在します。 It can be difficult to automatically work back to the original source construct that needs to be rewritten. このようなツールでは、本来のリファクタリング対象である展開のソースコードを自動的に書き換えることはできないかもしれません。

Template metaprogramming sometimes allows cleaner and easier-to-use interfaces than would be possible without it, but it's also often a temptation to be overly clever. テンプレートメタプログラミングは、使い方次第では、インターフェースをきれいで使いやすくするために役立ちます。しかし、それと同時に、必要以上に巧妙な実装をさせようとする挑戦への誘惑のかたまりでもあります。 It's best used in a small number of low level components where the extra maintenance burden is spread out over a large number of uses. テンプレートメタプログラミングは、そのコードの高いメンテナンスコストをたくさんの使用箇所で分散できるような少数の低レベルコンポーネントで用いるのが最適でしょう。

Think twice before using template metaprogramming or other complicated template techniques; think about whether the average member of your team will be able to understand your code well enough to maintain it after you switch to another project, or whether a non-C++ programmer or someone casually browsing the code base will be able to understand the error messages or trace the flow of a function they want to call. テンプレートメタプログラミングや、それに類する複雑なテンプレートテクニックを導入しようとする前に、一度立ち止まって次のことを考えてみてください。あなたのプロジェクトチームの平均的なメンバーは、あなたがチームを抜けた後でも、そのコードを十分に理解してメンテナンスできそうでしょうか? あるいは、C++を専門としないプログラマーや他の誰かが、カジュアルにそのコードベースを眺めたときに、エラーメッセージを理解したり、呼び出したい関数のプログラムの流れを追うことができそうでしょうか?  If you're using recursive template instantiations or type lists or metafunctions or expression templates, or relying on SFINAE or on the sizeof trick for detecting function overload resolution, then there's a good chance you've gone too far. もしあなたが、再帰的に、テンプレートのインスタンス化、型リスト、メタ関数、式テンプレートなどを使おうとしていたり、あるいは、SFINAEや、関数オーバーロード解決のためのsizeofトリックを使おうとしているのならば、それらは、おそらくやり過ぎであることを示しているでしょう。

If you use template metaprogramming, you should expect to put considerable effort into minimizing and isolating the complexity. テンプレートメタプログラミングを使うのであれば、その複雑さを最小化して分離することに対して、かなりの労力を費やすことになるでしょう。 You should hide metaprogramming as an implementation detail whenever possible, so that user-facing headers are readable, and you should make sure that tricky code is especially well commented. メタプログラミングのコードは、実装の詳細として可能な限り隠し、ユーザーが目にするヘッダーファイルを可能な限り読みやすく保ってください。 また、トリッキーなコードについては、特にしっかりとコメントを残すようにしてください。 You should carefully document how the code is used, and you should say something about what the "generated" code looks like. それらのコードがどのように使われるのかに注意してドキュメント化し、展開後のコードがどのような外観を持つのかについても言及してください。 Pay extra attention to the error messages that the compiler emits when users make mistakes. コードのユーザーが何かを間違えたときにコンパイラが生成するであろうエラーメッセージに、特別の気を配ってください。 The error messages are part of your user interface, and your code should be tweaked as necessary so that the error messages are understandable and actionable from a user point of view. これらのエラーメッセージはAPIにおけるユーザーインターフェースの一部なのです。 コードを使用するユーザーが何かを間違えてしまったとき、何が間違っていて何をすればいいのかわかるようなエラーメッセージが生成されるようにコードを調整してください。

コンセプトと制約

Use concepts sparingly. コンセプトは控えめに。 In general, concepts and constraints should only be used in cases where templates would have been used prior to C++20. 一般に、コンセプトと制約は、以前のC++であればテンプレートを使っていた場面に限って使用します。 Avoid introducing new concepts in headers, unless the headers are marked as internal to the library. ライブラリ内部でのみ使用するとマークしている場合を除いて、公開ヘッダーファイル内で新しいコンセプトを導入するのは避けてください。 Do not define concepts that are not enforced by the compiler. また、コンパイラによる強制が働かないコンセプトも定義してはいけません。 Prefer constraints over template metaprogramming, and avoid the template<Concept T> syntax; instead, use the requires(Concept<T>) syntax. 型に制約を課すときは、従来形式のテンプレートメタプログラミングよりも、新しい制約の機能を優先的に使用してください。 また、その際には、template<Concept T>の形の構文は避け、かわりにrequires(Concept<T>)の形を使ってください。

The concept keyword is a new mechanism for defining requirements (such as type traits or interface specifications) for a template parameter. conceptキーワードは、テンプレート引数に対して、型トレイトやインターフェース仕様等の要件を定義する新たな仕組みです。 The requires keyword provides mechanisms for placing anonymous constraints on templates and verifying that constraints are satisfied at compile time. requiresキーワードは、テンプレートにおいて無名の制約を課すための新たな仕組みであり、また、その制約が満たされていかどうかコンパイル時の検証を行わせるためにも使われます。 Concepts and constraints are often used together, but can be also used independently. コンセプトと制約は多くの場合に同時に用いられますが、それぞれを独立して用いることもできます。

Predefined concepts in the standard library should be preferred to type traits, when equivalent ones exist. 標準ライブラリにおいて、目的の型トレイトと同様のコンセプトとの両方が定義されているときは、コンセプトの方を優先的に用いましょう。 (e.g., if std::is_integral_v would have been used before C++20, then std::integral should be used in C++20 code.) (たとえば、今までstd::is_integral_vを使っていた箇所では、C++20ではstd::integralを使います。) Similarly, prefer modern constraint syntax (via requires(Condition)). 同様に、新しい制約の構文を、(requires(Condition)の形式で)優先的に用いましょう。 Avoid legacy template metaprogramming constructs (such as std::enable_if<Condition>) as well as the template<Concept T> syntax. template<Concept T>の構文や、 std::enable_if<Condition>のような従来形式のテンプレートメタプログラミングは避けましょう。

Do not manually re-implement any existing concepts or traits. 既存のコンセプトやトレイトを再実装してはいけません。 For example, use requires(std::default_initializable<T>) instead of requires(requires { T v; }) or the like. たとえば、requires(requires { T v; })のようなコードを書くのではなく、既存のrequires(std::default_initializable<T>)を使うようにしてください。

New concept declarations should be rare, and only defined internally within a library, such that they are not exposed at API boundaries. 新しいconceptを宣言することは控えましょう。新たにコンセプトを定義する場合であっても、ライブラリ内での内部利用にとどめ、API境界を越えてそれらが公開されることがないようにしてください。 More generally, do not use concepts or constraints in cases where you wouldn't use their legacy template equivalents in C++17. より一般には、今までのC++において同様のことをするテンプレートを使うべきでなかった箇所においては、同じくコンセプトや制約を使うべきではないということです。

Do not define concepts that duplicate the function body, or impose requirements that would be insignificant or obvious from reading the body of the code or the resulting error messages. 関数本体の複製となるようなコンセプトを定義してはいけません。 また、コード本体やエラーメッセージを読めば自明にわかるような、取るに足らない要件を課してもいけません。 For example, avoid the following:たとえば、次のようなコードは避けてください。

template <typename T>     // Bad - redundant with negligible benefit
concept Addable = std::copyable<T> && requires(T a, T b) { a + b; };
template <Addable T>
T Add(T x, T y, T z) { return x + y + z; }
template <typename T>     // 悪い例。冗長だし、メリットもない
concept Addable = std::copyable<T> && requires(T a, T b) { a + b; };
template <Addable T>
T Add(T x, T y, T z) { return x + y + z; }

Instead, prefer to leave code as an ordinary template unless you can demonstrate that concepts result in significant improvement for that particular case, such as in the resulting error messages for a deeply nested or non-obvious requirement. このようなケースでは、コンセプトは使わず、従来なからのただのテンプレート関数のままにしておく方が望ましいです。 コンセプトは、コンセプトを導入することによって、状況を大きく改善できる場合に限って用いるようにしてください。 たとえば、深くネストされた要件や、一目ではわかりにくいような要件などに対して、そのエラーメッセージを改善する目的などには、コンセプトは適役でしょう。

Concepts should be statically verifiable by the compiler. すべてのコンセプトは、コンパイラによって静的に検証可能なものでなければなりません。 Do not use any concept whose primary benefits would come from a semantic (or otherwise unenforced) constraint. 意味的な(あるいは、コンパイル時に強制されないような)制約条件によって主な利益がもたらされるコンセプトは使用してはいけません。 Requirements that are unenforced at compile time should instead be imposed via other mechanisms such as comments, assertions, or tests. コンパイル時のチェックが働かない(あるいは、できない)要件については、コンセプトや制約ではなく、コードコメントやアサーション、テストなどでそれらをカバーするようにしてください。

Boost

Use only approved libraries from the Boost library collection. Boostライブラリからは、そのライブラリコレクションのうち、あらかじめ認められたもののみを使うことができます。

The Boost library collection is a popular collection of peer-reviewed, free, open-source C++ libraries. Boostライブラリコレクションは、ピアレビュー済み、フリー、オープンソースの、有名なC++ライブラリのコレクションです。

Boost code is generally very high-quality, is widely portable, and fills many important gaps in the C++ standard library, such as type traits and better binders. Boostのコードは、全般にとても品質が良く、広い移植性があり、型トレイトや優れたバインダなどによって、C++標準ライブラリ内に散在するたくさんの隙間を埋めてくれます。

Some Boost libraries encourage coding practices which can hamper readability, such as metaprogramming and other advanced template techniques, and an excessively "functional" style of programming. いくつかのBoostライブラリでは、メタプログラミングやその他の先進的なテンプレートテクニックを積極的に取り入れていたり、関数型プログラミング言語のスタイルを採用していたりします。これらの手法はコードの可読性を妨げます。

In order to maintain a high level of readability for all contributors who might read and maintain code, we only allow an approved subset of Boost features. コードを読み、メンテナンスするすべてのコントリビュータのために、コードは高い可読性が保たれていなければなりません。この可読性を維持するために、Boostからは一部のサブセットのみについて、使用することを認めます。 Currently, the following libraries are permitted: 現時点では、以下のライブラリが使用を認められています。

We are actively considering adding other Boost features to the list, so this list may be expanded in the future. なお、他のBoostの機能についても、随時リストへの追加を検討していますので、将来的にこのリストは拡張されることがあります。

その他のC++機能

As with Boost, some modern C++ extensions encourage coding practices that hamper readability—for example by removing checked redundancy (such as type names) that may be helpful to readers, or by encouraging template metaprogramming. 前述のBoostも含め、現代的なC++を拡張するライブラリの中には、可読性の妨げとなるようなコーディング手法を取り入れているものもあります。 それらのコーディング手法では、たとえば、型名などの読者の助けになるはずの情報を冗長であるとして省いてしまっていたり、テンプレートメタプログラミングを積極的に採用していたりします。 Other extensions duplicate functionality available through existing mechanisms, which may lead to confusion and conversion costs. その他の様々な拡張は、既存の仕組みでも実現可能なことの繰り返しであり、これらは困惑の元になったり議論のコストを招いたりします。

In addition to what's described in the rest of the style guide, the following C++ features may not be used: 本ガイドの他のパートで説明している事柄に加えて、以下に示すC++の機能は使ってはいけません。

非標準の拡張

Nonstandard extensions to C++ may not be used unless otherwise specified. C++非標準の拡張は、特別に認められたものを除いて使ってはいけません。

Compilers support various extensions that are not part of standard C++. コンパイラは、様々なC++非標準の拡張を提供しています。 Such extensions include GCC's __attribute__, intrinsic functions such as __builtin_prefetch or SIMD, #pragma, inline assembly, __COUNTER__, __PRETTY_FUNCTION__, compound statement expressions (e.g., foo = ({ int x; Bar(&x); x }), variable-length arrays and alloca(), and the "Elvis Operator" a?:b.. このような非標準の拡張には、たとえばGCCがサポートしている、__attribute____builtin_prefetchやSIMDのような組み込み関数、#pragma、インラインアセンブリ、__COUNTER____PRETTY_FUNCTION__foo = ({ int x; Bar(&x); x })のような複合文、可変長配列とalloca()エルビス演算子(a?:b)などが含まれます。

Do not use nonstandard extensions. 非標準の拡張を使ってはいけません。 You may use portability wrappers that are implemented using nonstandard extensions, so long as those wrappers are provided by a designated project-wide portability header. なお、プロジェクトにおいて、非標準拡張機能を含む移植性の問題を解決することを目的とした、プロジェクト全体で使用するラッパーライブラリがある場合は、それらを通してこれらの機能を使用する分にはかまいません。

エイリアス

Public aliases are for the benefit of an API's user, and should be clearly documented. APIのユーザーのためのエイリアスのみを公開します。 また、公開するエイリアスについては明確なドキュメントを用意します。

There are several ways to create names that are aliases of other entities: C++において、他のエンティティへのエイリアスとして新しい名前を付けるには、いくつか方法があります。

typedef Foo Bar; // But prefer `using` in C++ code.
using ::other_namespace::Foo;
using enum MyEnumType;  // Creates aliases for all enumerators in MyEnumType.
typedef Foo Bar; // C++では `using` を使う方が好ましい
using ::other_namespace::Foo;
using enum MyEnumType;  // MyEnumTypeの全列挙子のエイリアスを作る

In new code, using is preferable to typedef, because it provides a more consistent syntax with the rest of C++ and works with templates. 新しく書くコードにおいては、typedefよりもusingを使う方が望ましいです。 usingの方が、よりC++の他の文法との一貫性があり、また、テンプレートとの相性も良いためです。

Like other declarations, aliases declared in a header file are part of that header's public API unless they're in a function definition, in the private portion of a class, or in an explicitly-marked internal namespace. Aliases in such areas or in .cc files are implementation details (because client code can't refer to them), and are not restricted by this rule. 他の宣言と同様に、ヘッダーファイルにおけるエイリアスの宣言は、その宣言が公開部分にある場合、同ヘッダーが提供するAPIの一部と見なされます。 一方で、エイリアスの宣言がクライアントコードから参照できない場所にある場合、たとえば、.ccファイル内にある場合や、ヘッダーファイル内であっても、関数内部や、クラスのprivateセクション、明示的に内部用と宣言された名前空間内に存在する場合は、それらの宣言は実装の詳細と見なされ、このルールで課す制限の対象外となります。

Don't put an alias in your public API just to save typing in the implementation; do so only if you intend it to be used by your clients. APIの公開部分には、クライアントコードによって使用されることを意図したエイリアスのみを宣言してください。それ以外の、たとえば実装時のタイピング数を減らす目的では、公開APIにエイリアスを宣言してはいけません。

When defining a public alias, document the intent of the new name, including whether it is guaranteed to always be the same as the type it's currently aliased to, or whether a more limited compatibility is intended. 公開エイリアスを定義するときは、そこで新しい名前を導入する目的をドキュメントに記述してください。 その際、エイリアスが、エイリアス先の型と常に同等であることが保証されているのか、あるいは、それよりももっと限定された互換性の範囲内でのみ使われることを想定して定義されているのかについての説明を含めてください。 This lets the user know whether they can treat the types as substitutable or whether more specific rules must be followed, and can help the implementation retain some degree of freedom to change the alias. これによって、APIのユーザーは、それらのエイリアスを型の単純な置き換えとして扱ってよいのか、あるいは、何らかのルールに従う必要があるのか判断することができるようになります。 同時に、その実装において、エイリアスの変更に対する一定の自由度を確保することもできるようになるでしょう。

Don't put namespace aliases in your public API. (See also Namespaces). 名前空間へのエイリアスを公開APIに含めてはいけません(名前空間を参照)。

For example, these aliases document how they are intended to be used in client code: 以下のコード例では、それぞれのエイリアスがクライアントコードからどのように扱われることを意図しているかについてドキュメント化しています。

namespace mynamespace {
// Used to store field measurements. DataPoint may change from Bar* to some internal type.
// Client code should treat it as an opaque pointer.
using DataPoint = ::foo::Bar*;

// A set of measurements. Just an alias for user convenience.
using TimeSeries = std::unordered_set<DataPoint, std::hash<DataPoint>, DataPointComparator>;
}  // namespace mynamespace
namespace mynamespace {
// フィールドの測定値を保存するために使います。
// DataPoint は Bar* から他の内部表現用の型に変更されるかもしれません。
// クライアントコードにおいては、これを透過的なポインタとして扱ってください。
using DataPoint = ::foo::Bar*;

// 測定値のセットを表します。
// このエイリアスは、単に利便性のために定義されています。
using TimeSeries = std::unordered_set<DataPoint, std::hash<DataPoint>, DataPointComparator>;
}  // namespace mynamespace

These aliases don't document intended use, and half of them aren't meant for client use: 一方で、次の例では、エイリアスの目的に関する記述がなく、また定義の半分についてはクライアントコードから使われることを想定したものですらありません。

namespace mynamespace {
// Bad: none of these say how they should be used.
using DataPoint = ::foo::Bar*;
using ::std::unordered_set;  // Bad: just for local convenience
using ::std::hash;           // Bad: just for local convenience
typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator> TimeSeries;
}  // namespace mynamespace
namespace mynamespace {
// 悪い例: どのように扱われるべきか書かれていない。
using DataPoint = ::foo::Bar*;
using ::std::unordered_set;  // ダメ: 実装の利便性のためだけに定義されている
using ::std::hash;           // ダメ: 実装の利便性のためだけに定義されている
typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator> TimeSeries;
}  // namespace mynamespace

However, local convenience aliases are fine in function definitions, private sections of classes, explicitly marked internal namespaces, and in .cc files: ただし、関数定義の中など、クライアントコードからアクセスできない場所であれば、このような実装の利便性のためのエイリアスを定義してもかまいません。同様に、クラスのprivateセクション、明示的に内部利用とマークされた名前空間の中、.ccファイル内などにおける定義も同様に問題ありません。

// In a .cc file
using ::foo::Bar;
// .ccファイル内
using ::foo::Bar;

switch文

If not conditional on an enumerated value, switch statements should always have a default case (in the case of an enumerated value, the compiler will warn you if any values are not handled). switch文の条件式が列挙型でない場合は、必ずdefaultブロックが必要です。 (列挙型の値によるswitch文については、対応漏れがある場合にコンパイラが警告してくれるでしょう。) If the default case should never execute, treat this as an error. For example: プログラムの構造上、defaultブロックが実行される機会は絶対にないという場合には、次の例のようにエラーとして扱うようにしてください。

switch (var) {
  case 0: {
    ...
    break;
  }
  case 1: {
    ...
    break;
  }
  default: {
    LOG(FATAL) << "Invalid value in switch statement: " << var;
  }
}

Fall-through from one case label to another must be annotated using the [[fallthrough]]; attribute. あるcaseラベルから別のラベルへフォールスルーさせる場合は、必ず[[fallthrough]];属性でマークしてください。 [[fallthrough]]; should be placed at a point of execution where a fall-through to the next case label occurs. [[fallthrough]];は次のラベルへのフォールスルーがまさに起こる場所に記述します。 A common exception is consecutive case labels without intervening code, in which case no annotation is needed. ただし、間にコードを含まずcaseラベルが連続している場合には、マークは不要です。

switch (x) {
  case 41:  // No annotation needed here.
  case 43:
    if (dont_be_picky) {
      // Use this instead of or along with annotations in comments.
      [[fallthrough]];
    } else {
      CloseButNoCigar();
      break;
    }
  case 42:
    DoSomethingSpecial();
    [[fallthrough]];
  default:
    DoSomethingGeneric();
    break;
}
switch (x) {
  case 41:  // ここには [[fallthrough]]; は不要です。
  case 43:
    if (dont_be_picky) {
      // コメントのかわりに(あるいは、コメントとともに)、
      // このようにマークします。
      [[fallthrough]];
    } else {
      CloseButNoCigar();
      break;
    }
  case 42:
    DoSomethingSpecial();
    [[fallthrough]];
  default:
    DoSomethingGeneric();
    break;
}

インクルーシブ・ランゲージ

In all code, including naming and comments, use inclusive language and avoid terms that other programmers might find disrespectful or offensive (such as "master" and "slave", "blacklist" and "whitelist", or "redline"), even if the terms also have an ostensibly neutral meaning. 命名やコメントを含むすべてのコードにおいて「インクルーシブ・ランゲージ」を使用します。 他のプログラマーにとって、無礼または不快に感じられる可能性のある用語 (「マスター」と「スレーブ」、「ブラックリスト」と「ホワイトリスト」、または「レッドライン」など) は、その用語の表面上の意味が中立的なものであったとしても、使用するのを避けてください。 Similarly, use gender-neutral language unless you're referring to a specific person (and using their pronouns). 同様に、ある特定の人(および、その人の代名詞)に言及しようとしている場合を除き、ジェンダーに中立な言葉を使用してください。 For example, use "they"/"them"/"their" for people of unspecified gender (even when singular), and "it"/"its" for software, computers, and other things that aren't people. たとえば、ジェンダーを特定せずに人を指す言葉として(単数の場合でも) "they" / "them" / "their" を使用します。"it" / "its" は、ソフトウェアやコンピューターなどのものに対して使用し、人に対しては用いません。

命名規則

The most important consistency rules are those that govern naming. コードの一貫性を保つためのもっとも重要なルールは、名前の付け方を決めることです。 The style of a name immediately informs us what sort of thing the named entity is: a type, a variable, a function, a constant, a macro, etc., without requiring us to search for the declaration of that entity. 名前のスタイルを適切に定めることで、それが何であるか、すなわち、型なのか、変数なのか、関数なのか、定数なのか、マクロなのか、その宣言を探すことなく、すぐにわかるようにすることができます。 The pattern-matching engine in our brains relies a great deal on these naming rules. 私たちの脳がもつパターンマッチングエンジンは、こうした命名規則に大きく依存しています。

Naming rules are pretty arbitrary, but we feel that consistency is more important than individual preferences in this area, so regardless of whether you find them sensible or not, the rules are the rules. 命名規則はかなり恣意的なものですが、私たちは、この領域において、個人の好みよりも、一貫性が保たれることを重要視しています。 ですので、以下で定める命名規則については、あなたにとってわかりやすいと感じるかどうかに関わらず、「ルールはルール」と考えるようにしてください。

全般的な命名規則

Optimize for readability using names that would be clear even to people on a different team. プロジェクトチーム外のプログラマーから見ても、その意図が明確に伝わるような命名を行い、コードの可読性を最適化してください。

Use names that describe the purpose or intent of the object. オブジェクトには、そのオブジェクトの目的や意図を説明する名前を付けてください。 Do not worry about saving horizontal space as it is far more important to make your code immediately understandable by a new reader. 画面の横幅を節約する必要はありません。そんなことよりも、コードを新しい読者でも直感的に理解できるようにしておくことの方がはるかに重要です。 Minimize the use of abbreviations that would likely be unknown to someone outside your project (especially acronyms and initialisms). プロジェクトチーム外の読者が知らないかもしれない省略語(特に、頭字語やイニシャル化すること)は最小限にとどめてください。 Do not abbreviate by deleting letters within a word. また、単語の中の文字を削って省略系を作ってもいけません。 As a rule of thumb, an abbreviation is probably OK if it's listed in Wikipedia. 経験則的には、Wikipediaに載っているような省略系であれば概ねOKと言えるでしょう。 Generally speaking, descriptiveness should be proportional to the name's scope of visibility. 一般論として、名前は、その名前が見えるスコープの大きさに比例してその詳細度を決めるようにします。 For example, n may be a fine name within a 5-line function, but within the scope of a class, it's likely too vague. たとえば、「n」という名前は、5行しかない関数の中であれば悪くはない命名ですが、クラススコープ変数に同じ命名を行ったとしたら、意味が曖昧すぎるでしょう。

class MyClass {
 public:
  int CountFooErrors(const std::vector<Foo>& foos) {
    int n = 0;  // Clear meaning given limited scope and context
    for (const auto& foo : foos) {
      ...
      ++n;
    }
    return n;
  }
  void DoSomethingImportant() {
    std::string fqdn = ...;  // Well-known abbreviation for Fully Qualified Domain Name
  }
 private:
  const int kMaxAllowedConnections = ...;  // Clear meaning within context
};
class MyClass {
 public:
  int CountFooErrors(const std::vector<Foo>& foos) {
    int n = 0;  // スコープと文脈が限られているため十分明確
    for (const auto& foo : foos) {
      ...
      ++n;
    }
    return n;
  }
  void DoSomethingImportant() {
    std::string fqdn = ...;  // 一般的によく使われる、Fully Qualified Domain Name の略語
  }
 private:
  const int kMaxAllowedConnections = ...;  // この文脈において意味が明確
}; 
class MyClass {
 public:
  int CountFooErrors(const std::vector<Foo>& foos) {
    int total_number_of_foo_errors = 0;  // Overly verbose given limited scope and context
    for (int foo_index = 0; foo_index < foos.size(); ++foo_index) {  // Use idiomatic `i`
      ...
      ++total_number_of_foo_errors;
    }
    return total_number_of_foo_errors;
  }
  void DoSomethingImportant() {
    int cstmr_id = ...;  // Deletes internal letters
  }
 private:
  const int kNum = ...;  // Unclear meaning within broad scope
};
class MyClass {
 public:
  int CountFooErrors(const std::vector<Foo>& foos) {
    int total_number_of_foo_errors = 0;  // 十分に狭いスコープと文脈に対して、名前が冗長すぎ
    for (int foo_index = 0; foo_index < foos.size(); ++foo_index) {  // 慣用的`i`を使うべき
      ...
      ++total_number_of_foo_errors;
    }
    return total_number_of_foo_errors;
  }
  void DoSomethingImportant() {
    int cstmr_id = ...;  // 単語の途中の文字が削られていると読みにくい
  }
 private:
  const int kNum = ...;  // スコープが広く、何を表すのか不明瞭
};

Note that certain universally-known abbreviations are OK, such as i for an iteration variable and T for a template parameter. なお、イテレーション変数のi、テンプレート引数のTなど、一般に広く知られている短縮形を用いることは問題ありません。

For the purposes of the naming rules below, a "word" is anything that you would write in English without internal spaces. これ以降の命名規則のルールにおいて、「単語」とは、英語で書くときにスペースを含まずに綴られるもののことを指すとします。 This includes abbreviations, such as acronyms and initialisms. これには、頭字語やイニシャルなどの略語も含みます。 For names written in mixed case (also sometimes referred to as "camel case" or "Pascal case"), in which the first letter of each word is capitalized, prefer to capitalize abbreviations as single words, e.g., StartRpc() rather than StartRPC(). 各単語の頭文字を大文字として大文字小文字を混在させる命名(「キャメルケース」または「パスカルケース」と呼ばれるもの)を行う際には、略語も1つの単語であるかのように表記します。例えば StartRPC()ではなくStartRpc()とします。

Template parameters should follow the naming style for their category: type template parameters should follow the rules for type names, and non-type template parameters should follow the rules for variable names. テンプレート引数の命名規則は、それぞれの引数が属するカテゴリに従います。 つまり、テンプレート引数が型引数ならば型の命名規則に従い、それ以外の非型引数は変数の命名規則に従います。

ファイル名

Filenames should be all lowercase and can include underscores (_) or dashes (-). ファイル名はすべて小文字とします。アンダースコア(_)かダッシュ(-)を含めてもかまいません。 Follow the convention that your project uses. プロジェクトで採用している命名規則に従ってください。 If there is no consistent local pattern to follow, prefer "_". 従うべき一貫したルールが定められていない場合には、アンダースコアを使ってください。

Examples of acceptable file names: 例として、次のようなファイル名は問題ありません。

C++ files should end in .cc and header files should end in .h. ソースファイルの拡張子は.cc、ヘッダーファイルの拡張子は.hとします。 Files that rely on being textually included at specific points should end in .inc (see also the section on self-contained headers). 特定の場所にそのままインクルードされることを意図しているファイルには、拡張子.incをつけます(自己完結型ヘッダーのセクションも参照してください)。

Do not use filenames that already exist in /usr/include, such as db.h. 既に/usr/includeに存在するファイル名(たとえばdb.hなど)をつけてはいけません。

In general, make your filenames very specific. 一般に、ファイル名は非常に具体的な名前となるようにしてください。 For example, use http_server_logs.h rather than logs.h. たとえば、単にlogs.hとはせず、http_server_logs.hのような命名を行ってください。 A very common case is to have a pair of files called, e.g., foo_bar.h and foo_bar.cc, defining a class called FooBar. 非常に良くあるパターンは、ファイルのペアfoo_bar.hfoo_bar.ccでクラスFooBarを定義するようなやり方です。

型名

Type names start with a capital letter and have a capital letter for each new word, with no underscores: MyExcitingClass, MyExcitingEnum. 型の名前は大文字で始め、単語ごとの頭文字を大文字にします。アンダースコアは使いません。たとえば、MyExcitingClassMyExcitingEnumのようにします。

The names of all types — classes, structs, type aliases, enums, and type template parameters — have the same naming convention. 型に類するもの、すなわちクラス、構造体、型のエイリアス、列挙型、型テンプレート引数はすべて、この規則に従って命名します。 Type names should start with a capital letter and have a capital letter for each new word. 型の名前は大文字で始めて、新しい単語ごとに頭文字を大文字にします。 No underscores. アンダースコアは使いません。 For example: 以下に例を示します。

// classes and structs
class UrlTable { ...
class UrlTableTester { ...
struct UrlTableProperties { ...

// typedefs
typedef hash_map<UrlTableProperties *, std::string> PropertiesMap;

// using aliases
using PropertiesMap = hash_map<UrlTableProperties *, std::string>;

// enums
enum class UrlTableError { ...
// クラスと構造体
class UrlTable { ...
class UrlTableTester { ...
struct UrlTableProperties { ...

// typedef
typedef hash_map<UrlTableProperties *, std::string> PropertiesMap;

// usingエイリアス
using PropertiesMap = hash_map<UrlTableProperties *, std::string>;

// 列挙型
enum class UrlTableError { ...

変数名

The names of variables (including function parameters) and data members are snake_case (all lowercase, with underscores between words). 変数や関数引数、データメンバーの名前には、snake_case(すべて小文字、単語間はアンダースコア)を使います。 Data members of classes (but not structs) additionally have trailing underscores. 構造体を除くクラスのデータメンバ名には、末尾に追加のアンダースコアをつけます。 For instance: a_local_variable, a_struct_data_member, a_class_data_member_. たとえば、それぞれ、a_local_variablea_struct_data_membera_class_data_member_のようにします。

一般的な変数名

For example: 以下に例を示します。

std::string table_name;  // OK - snake_case.
std::string table_name;  // OK - snake_caseになっている
std::string tableName;   // Bad - mixed case.
std::string tableName;   // ダメ - 大文字小文字が混ざっている。

クラスのデータメンバ

Data members of classes, both static and non-static, are named like ordinary nonmember variables, but with a trailing underscore. クラスのデータメンバは、staticの有無にかかわらず、通常の変数と同様の命名を行い、さらに、末尾に追加のアンダースコアをつけます。

class TableInfo {
  ...
 private:
  std::string table_name_;  // OK - underscore at end.
  static Pool<TableInfo>* pool_;  // OK.
};
class TableInfo {
  ...
 private:
  std::string table_name_;  // OK。末尾にアンダースコア
  static Pool<TableInfo>* pool_;  // OK。
};

構造体のデータメンバ

Data members of structs, both static and non-static, are named like ordinary nonmember variables. 構造体のデータメンバは、staticの有無にかかわらず、通常の変数と同じように名前を付けます。 They do not have the trailing underscores that data members in classes have. クラスのデータメンバとは異なり、末尾にアンダースコアはつけません。

struct UrlTableProperties {
  std::string name;
  int num_entries;
  static Pool<UrlTableProperties>* pool;
};

See Structs vs. Classes for a discussion of when to use a struct versus a class. 構造体とクラスの使い分けに関する議論については、構造体か、クラスかを参照してください。

定数名

Variables declared constexpr or const, and whose value is fixed for the duration of the program, are named with a leading "k" followed by mixed case. constexprconstで宣言され、かつ、プログラムの最初から最後まで常に不変の固定の値をもつ変数は、頭に「k」をつけた上で、大文字小文字混じりの名前を付けます。 Underscores can be used as separators in the rare cases where capitalization cannot be used for separation. 単語の境界において大文字化することができない場合は、アンダースコアを区切りとして使ってもかまいません。 For example: 以下に例を示します。

const int kDaysInAWeek = 7;
const int kAndroid8_0_0 = 24;  // Android 8.0.0

All such variables with static storage duration (i.e., statics and globals, see Storage Duration for details) should be named this way, including those in templates where different instantiations of the template may have different values. このような、値が不変の静的記憶域時間の定数変数(すなわち、静的変数やグローバル変数ですが、詳細はStorage Durationを参照してください)は、この規則に従って命名します。これには、テンプレートの静的変数について、それらの値がテンプレートインスタンスごとに異なる場合も含みます。 This convention is optional for variables of other storage classes, e.g., automatic variables; otherwise the usual variable naming rules apply. それ以外の記憶域期間に分類される定数変数(自動変数など)については、この命名規則に従うか、あるいは、通常の変数と同様の命名規則に従うかのいずれか任意とします。

void ComputeFoo(absl::string_view suffix) {
  // Either of these is acceptable.
  const absl::string_view kPrefix = "prefix";
  const absl::string_view prefix = "prefix";
  ...
}
void ComputeFoo(absl::string_view suffix) {
  // 以下のどちらでもOKです
  const absl::string_view kPrefix = "prefix";
  const absl::string_view prefix = "prefix";
  ...
}
void ComputeFoo(absl::string_view suffix) {
  // Bad - different invocations of ComputeFoo give kCombined different values.
  const std::string kCombined = absl::StrCat(kPrefix, suffix);
  ...
}
void ComputeFoo(absl::string_view suffix) {
  // これはダメ。kCombined が関数呼び出し毎に異なる値になりうる
  const std::string kCombined = absl::StrCat(kPrefix, suffix);
  ...
}

関数名

Regular functions have mixed case; accessors and mutators may be named like variables. 通常の関数は、大文字小文字を混ぜて命名します。なお、getter関数やsetter関数は、変数名の命名規則に従ってもかまいません。

Ordinarily, functions should start with a capital letter and have a capital letter for each new word. 通常は、関数名は大文字で始めて、単語ごとに頭文字を大文字にします。

AddTableEntry()
DeleteUrl()
OpenFileOrDie()

(The same naming rule applies to class- and namespace-scope constants that are exposed as part of an API and that are intended to look like functions, because the fact that they're objects rather than functions is an unimportant implementation detail.) (クラススコープや名前空間スコープにおいて、APIの一部として公開される、関数のように振る舞う定数オブジェクトについても、関数名の命名規則を適用してください。これらが実際のところはオブジェクトであり、関数ではないという事実は、APIのユーザーの視点からはあまり重要ではない実装の詳細であると言えるからです。)

Accessors and mutators (get and set functions) may be named like variables. getter関数やsetter関数は、変数のような名前を付けてもかまいません。 These often correspond to actual member variables, but this is not required. また、これらの関数は、実在のメンバ変数と紐づけられることが多いですが、必ずしもそうでなくてもかまいません。 For example, int count() and void set_count(int count). たとえば、int count()void set_count(int count)のようにしてもかまいません。

名前空間の名前

Namespace names are all lower-case, with words separated by underscores. 名前空間の名前は、すべて小文字で、単語間はアンダースコアで区切ります。 Top-level namespace names are based on the project name. トップレベル(最も外側)の名前空間には、プロジェクト名に基づいた名前を付けます。 Avoid collisions between nested namespaces and well-known top-level namespaces. また、ネストされた名前空間であっても、よく知られたトップレベル名前空間の名前と衝突させるのは避けてください。

The name of a top-level namespace should usually be the name of the project or team whose code is contained in that namespace. トップレベル名前空間の名前には、通常はプロジェクト名かチーム名を付けます。 The code in that namespace should usually be in a directory whose basename matches the namespace name (or in subdirectories thereof). 名前空間に含まれるコードは、通常は名前空間の名前と同名のディレクトリ(か、そのサブディレクトリ)に置きます。

Keep in mind that the rule against abbreviated names applies to namespaces just as much as variable names. 名前空間の名前を付けるときにも、変数名と同様に省略系に関するルールが適用されることに注意してください。 Code inside the namespace seldom needs to mention the namespace name, so there's usually no particular need for abbreviation anyway. 名前空間内のコードにおいて、それを囲む名前空間の名前を必要とすることはほとんどありませんので、いずれにせよ、名前空間名に省略系を使う需要はないはずです。

Avoid nested namespaces that match well-known top-level namespaces. ネストされた名前空間であっても、よく知られたトップレベル名前空間の名前と同じ名前は付けないでください。 Collisions between namespace names can lead to surprising build breaks because of name lookup rules. そのような名前空間名の衝突があると、名前検索のルールによって、想定外のビルドエラーを引き起こすことがあります。 In particular, do not create any nested std namespaces. 特に、stdという名前の名前空間は、いかなる階層であっても作ってはいけません。 Prefer unique project identifiers (websearch::index, websearch::index_util) over collision-prone names like websearch::util. プロジェクト名自体にもなるべくユニークとなる識別子をつけることが望ましいです。 たとえば、websearch::utilのような衝突しやすい名前よりも、websearch::indexwebsearch::index_utilのような名前にします。 Also avoid overly deep nesting namespaces (TotW #130). また、名前空間のネストを深くしすぎないようにしてください(TotW #130)。

For internal namespaces, be wary of other code being added to the same internal namespace causing a collision (internal helpers within a team tend to be related and may lead to collisions). internal名前空間においては、同じinternal名前空間に追加される他のコードと衝突しないように、特に注意が必要です。(チーム内向けのヘルパー同士がこの関係に陥る傾向があり、ときに衝突につながります)。 In such a situation, using the filename to make a unique internal name is helpful (websearch::index::frobber_internal for use in frobber.h) このような場合には、ファイル名を使ってユニークな名前を作る方法が役立ちます(たとえばfrobber.hでは、websearch::index::frobber_internalのようにします)。

列挙型の名前

Enumerators (for both scoped and unscoped enums) should be named like constants, not like macros. That is, use kEnumName not ENUM_NAME. 列挙型(スコープ付き、スコープなしの両方とも)は、定数の命名規則(kEnumName)に従います。マクロの命名規則(ENUM_NAME)は使いません。

enum class UrlTableError {
  kOk = 0,
  kOutOfMemory,
  kMalformedInput,
};
enum class AlternateUrlTableError {
  OK = 0,
  OUT_OF_MEMORY = 1,
  MALFORMED_INPUT = 2,
};

Until January 2009, the style was to name enum values like macros. 2009年1月までは、列挙値はマクロの命名規則に従っていましたが、 This caused problems with name collisions between enum values and macros. 列挙値とマクロとの間で名前が衝突する問題が起きたため、 Hence, the change to prefer constant-style naming was put in place. 列挙型の名前は定数の命名規則に従うようルールが変更されました。 New code should use constant-style naming. 新しく書くコードでは定数の命名規則に従ってください。

マクロの名前

You're not really going to define a macro, are you? If you do, they're like this: MY_MACRO_THAT_SCARES_SMALL_CHILDREN_AND_ADULTS_ALIKE. 本当はマクロを定義しようだなんて思ってないですよね……?  マクロを定義する場合は、MY_MACRO_THAT_SCARES_SMALL_CHILDREN_AND_ADULTS_ALIKE((訳注:「小さな子供も大人も同じように怖がらせる私のマクロ」の意)) のように名前をつけます。

Please see the description of macros; in general macros should not be used. まず、マクロの詳細を確認してください。通常、マクロを使うべきではありません However, if they are absolutely needed, then they should be named with all capitals and underscores, and with a project-specific prefix. それでも、どうしてもマクロが必要な場合は、すべてを大文字にし、アンダースコアで単語を区切り、さらにプロジェクト固有の接頭辞をつけて命名してください。

#define MYPROJECT_ROUND(x) ...

命名規則の例外

If you are naming something that is analogous to an existing C or C++ entity then you can follow the existing naming convention scheme. 名前をつけようとしている対象がC言語やC++における既存のエンティティと類似している場合は、それらに倣った命名規則に従ってもかまいません。

bigopen()
function name, follows form of open() open()の形に倣った関数名
uint
typedef
bigpos
struct or class, follows form of pos posの形に倣ったstructclass
sparse_hash_map
STL-like entity; follows STL naming conventions STLの命名規則に倣ったSTL風エンティティ
LONGLONG_MAX
a constant, as in INT_MAX INT_MAXに倣った定数

コメント

Comments are absolutely vital to keeping our code readable. コードの可読性を保つためには、コメントが絶対に必要不可欠です。 The following rules describe what you should comment and where. 以下のルールでは、どこにどのようなコメントを残すべきか説明します。 But remember: while comments are very important, the best code is self-documenting. ただし、確かにコメントは非常に重要で、それは間違いありませんが、それよりも最もベストなのは、コード自身が自分で自分の意味を説明できていることです。 Giving sensible names to types and variables is much better than using obscure names that you must then explain through comments. 型や変数に明確で伝わりやすい名前をつけることは、曖昧な命名をしてコメントで説明するよりも、はるかに優れています。

When writing your comments, write for your audience: the next contributor who will need to understand your code. コメントを書くときは、その読者に宛てるつもりで書いてください。 つまり、そのコードを次に担当するメンバーが、そのコードを理解できるようになるために、コメントを書いてください。 Be generous — the next one may be you! ひょっとすると、次のコードの担当者はあなた自身かもしれません。コメントは惜しみなく書きましょう。

((訳注: この日本語翻訳版ガイドではコード例の中のコメントも日本語に訳してありますが、本ガイドのルールはあくまで英語のコメントを対象としており、本翻訳版も英語コメントを対象としたもののまま訳していますので注意してください。とはいえ、これらのコメントの書き方のルールについては、日本語でコメントを書く場合でも大いに適用できる部分があると訳者は考えます。))

コメントのスタイル

Use either the // or /* */ syntax, as long as you are consistent. コメントは、一貫性が保たれている限り、///* */のどちらの文法を使ってもかまいません。

You can use either the // or the /* */ syntax; however, // is much more common. コメントは、///* */のどちらの文法で書いてもかまいません。ただし、//を用いる方がはるかに一般的です。 Be consistent with how you comment and what style you use where. どのようにコメントを書くか、どのスタイルに従うかについて、一貫性を保ってください。

ファイルに対するコメント

Start each file with license boilerplate. 各ファイルは、ライセンスに関する定型文で始めてください。

If a source file (such as a .h file) declares multiple user-facing abstractions (common functions, related classes, etc.), include a comment describing the collection of those abstractions. あるソースファイル(.hファイル等)において、公開APIとしての抽象(共通関数や関連クラス等)を複数宣言している場合には、それら全体を総括的に説明するコメントを含めてください。 Include enough detail for future authors to know what does not fit there. また、コードの将来のメンテナーがそれを読んだとき、何をそこに含めるのがふさわしく、何がふさわしくないのか判断できるような、十分な説明を含めてください。 However, the detailed documentation about individual abstractions belongs with those abstractions, not at the file level. なお、そのファイルに含まれる個々の抽象に関する詳細な情報は、ファイルレベルのコメントではなく、それぞれの抽象に属するようにしてください。

For instance, if you write a file comment for frobber.h, you do not need to include a file comment in frobber.cc or frobber_test.cc. 例として、frobber.hにファイルコメントを書くのであれば、frobber.ccfrobber_test.ccにはファイルコメントを書く必要はありません。 On the other hand, if you write a collection of classes in registered_objects.cc that has no associated header file, you must include a file comment in registered_objects.cc. 反対に、たとえば、registered_objects.ccにクラスのコレクションを書いていて、そのファイルと対応するヘッダーファイルが存在しないのであれば、registered_objects.ccにファイルレベルのコメントを含めるようにしてください。

法的通知と著者に関する行

Every file should contain license boilerplate. すべてのファイルに、ライセンスに関する定型文を含めてください。 Choose the appropriate boilerplate for the license used by the project (for example, Apache 2.0, BSD, LGPL, GPL). その際、そのプロジェクトが採用するライセンス(たとえば、Apache 2.0, BSD, LGPL, GPL等)に応じて、適切な定型文を選んでください。

If you make significant changes to a file with an author line, consider deleting the author line. あるファイルを大きく変更した場合は、そのファイルの著者に関する行(存在する場合)を削除することを検討してください。 New files should usually not contain copyright notice or author line. 新しく作るファイルについては、通常は、著作権表記や著者の行は含めません。

構造体やクラスに対するコメント

Every non-obvious class or struct declaration should have an accompanying comment that describes what it is for and how it should be used. 極めて単純なものを除いて、クラスや構造体の宣言には、その型の目的と使い方に関するコメントを書いてください。

// Iterates over the contents of a GargantuanTable.
// Example:
//    std::unique_ptr<GargantuanTableIterator> iter = table->NewIterator();
//    for (iter->Seek("foo"); !iter->done(); iter->Next()) {
//      process(iter->key(), iter->value());
//    }
class GargantuanTableIterator {
  ...
};
// GargantuanTable全体をイテレートします
// 使用例:
//    std::unique_ptr<GargantuanTableIterator> iter = table->NewIterator();
//    for (iter->Seek("foo"); !iter->done(); iter->Next()) {
//      process(iter->key(), iter->value());
//    }
class GargantuanTableIterator {
  ...
};
((訳注: Gargantuan: 途方もないくらい大きな))

クラスに対するコメント

The class comment should provide the reader with enough information to know how and when to use the class, as well as any additional considerations necessary to correctly use the class. クラスのコメントには、そのクラスをいつ・どのように用いれば良いかがわかるように、また、そのクラスを正しく扱うための付加的な考慮事項がある場合はそれらに関しても、十分な情報を含めるようにしてください。 Document the synchronization assumptions the class makes, if any. クラスが、同期に関する前提条件を持つ場合には、それらについても記述してください。 If an instance of the class can be accessed by multiple threads, take extra care to document the rules and invariants surrounding multithreaded use. クラスのインスタンスが複数のスレッドからのアクセスを受け入れるのであれば、マルチスレッド下でそれらを扱う際のルールや不変条件に関して、細心の注意を払って記述してください。

The class comment is often a good place for a small example code snippet demonstrating a simple and focused usage of the class. クラスのコメントは、そのクラスの使用例などの小さなコードスニペットを記述するのにも都合の良い場所です。

When sufficiently separated (e.g., .h and .cc files), comments describing the use of the class should go together with its interface definition; comments about the class operation and implementation should accompany the implementation of the class's methods. コードが.h.ccファイルとに十分に分離されているときは、クラスの使い方に関する内容をインターフェース定義のコメントに記述し、クラスが行う操作や実装に関する内容をメソッドの実装のコメントに記述してください。

関数に対するコメント

Declaration comments describe use of the function (when it is non-obvious); comments at the definition of a function describe operation. 関数宣言のコメントでは、その関数の使い方について (それが、明白でない場合) 説明してください。関数定義のコメントでは、関数によって行われる操作について説明してください。

関数宣言時のコメント

Almost every function declaration should have comments immediately preceding it that describe what the function does and how to use it. ほとんどすべての関数宣言において、その宣言の直前に、関数の目的 (その関数が何をするのか) とその使用方法に関するコメントが必要です。 These comments may be omitted only if the function is simple and obvious (e.g., simple accessors for obvious properties of the class). 関数が非常にシンプルで明らかな場合はコメントを省略してもかまいません。 たとえば、クラスのデータメンバに対するgetter関数などではコメントを書く必要はありません。 Private methods and functions declared in .cc files are not exempt. なお、プライベートメソッドや、.cc内で宣言された関数だからといって、コメントが免除されるわけではありません。 Function comments should be written with an implied subject of This function and should start with the verb phrase; for example, "Opens the file", rather than "Open the file". 関数コメントは、This function(この関数は)を暗黙的な主語として、動詞句から始めます。 たとえば、"Opens the file(ファイルを開きます)"です。"Open the file(ファイルを開け)" ではありません((訳注: 英文法の三単現の`s`のことを言っています))。 In general, these comments do not describe how the function performs its task. 一般に、これらの関数宣言時のコメントでは、どのように処理が行われるかについては触れません。 Instead, that should be left to comments in the function definition. そのような内容は、関数宣言時ではなく、関数定義時のコメントに譲ってください。

Types of things to mention in comments at the function declaration: 関数宣言時のコメントで言及すべきことは以下のような内容です。

Here is an example: 以下に例を示します。

// Returns an iterator for this table, positioned at the first entry
// lexically greater than or equal to `start_word`. If there is no
// such entry, returns a null pointer. The client must not use the
// iterator after the underlying GargantuanTable has been destroyed.
//
// This method is equivalent to:
//    std::unique_ptr<Iterator> iter = table->NewIterator();
//    iter->Seek(start_word);
//    return iter;
std::unique_ptr<Iterator> GetIterator(absl::string_view start_word) const;
// テーブル内で`start_word`に等しいか辞書的に次に大きい最初の要素を指す
// イテレータを返します。そのような要素がない場合、nullptrが返ります。
// 対象のGargantuanTableが破壊された後は、この関数から戻ったイテレータを
// 使用してはいけません。
//
// このメソッドは次の呼び出しと等価です:
//    std::unique_ptr<Iterator> iter = table->NewIterator();
//    iter->Seek(start_word);
//    return iter;
std::unique_ptr<Iterator> GetIterator(absl::string_view start_word) const;

However, do not be unnecessarily verbose or state the completely obvious. ただし、コメントを無用に冗長にしたり、完全に明白なことをわざわざ主張したりはしないでください。

When documenting function overrides, focus on the specifics of the override itself, rather than repeating the comment from the overridden function. オーバーライドした関数にドキュメントを書くときは、オーバーライドする前の関数と同等のコメントを繰り返すのではなく、そのオーバーライド自体の内容にフォーカスしたコメントを記述してください。 In many of these cases, the override needs no additional documentation and thus no comment is required. ただし、多くの場合において、関数のオーバーライド時に追加の情報を必要とすることはありませんので、そのような場合には、あえてコメントする必要はありません。

When commenting constructors and destructors, remember that the person reading your code knows what constructors and destructors are for, so comments that just say something like "destroys this object" are not useful. コンストラクタやデストラクタにコメントを書くときは、コードの読者は、コンストラクタとは何か、デストラクタとは何か、既に知っているということに注意してください。「オブジェクトを破壊します」というコメントには何の情報もありません。 Document what constructors do with their arguments (for example, if they take ownership of pointers), and what cleanup the destructor does. コンストラクタのコメントでは、コンストラクタが与えられた引数をどう扱うのか (たとえば、ポインタの所有権を引き取るか否か) について説明してください。デストラクタのコメントでは、デストラクタが何をクリーンアップするかについて記述します。 If this is trivial, just skip the comment. わざわざ説明するまでもなければ、コメントを省略してかまいません。 It is quite common for destructors not to have a header comment. 実際、デストラクタのヘッダーコメントは省略されるのが極めて一般的です。

関数定義時のコメント

If there is anything tricky about how a function does its job, the function definition should have an explanatory comment. 関数がその処理において何かしらトリッキーなことをしている場合には、関数定義のコメントで、それらについて説明してください。 For example, in the definition comment you might describe any coding tricks you use, give an overview of the steps you go through, or explain why you chose to implement the function in the way you did rather than using a viable alternative. 関数定義のコメントでは、たとえば、関数の実装で使われているコーディングトリックを説明したり、関数の処理手順の概要を示したり、あるいは、様々な実装方法の中からその方法を選んだ理由を説明したりすることができます。 For instance, you might mention why it must acquire a lock for the first half of the function but why it is not needed for the second half. 具体的な例として、たとえば、関数前半ではロックの取得を必要とするが、関数後半では不要となる理屈について説明することもできるでしょう。

Note you should not just repeat the comments given with the function declaration, in the .h file or wherever. なお、ヘッダーファイル等で行った関数宣言時のコメントを繰り返すだけのコメントは避けてください。 It's okay to recapitulate briefly what the function does, but the focus of the comments should be on how it does it. 関数の目的を軽く繰り返す程度はかまいませんが、関数定義時のコメントでは、どちらかといえば、どのようにそれを実現するのかについてフォーカスしたコメントを記述してください。

変数に対するコメント

In general the actual name of the variable should be descriptive enough to give a good idea of what the variable is used for. 一般に、変数の名前には、その変数が何のために使われているか、その目的がわかるような、十分に説明的な名前をつけているはずです。 In certain cases, more comments are required. それでも、さらなるコメントを必要とするケースがありますので、ここではそれについて説明します。

クラスデータメンバに対するコメント

The purpose of each class data member (also called an instance variable or member variable) must be clear. クラスの各データメンバ(メンバ変数)の目的は明確でなければなりません。 If there are any invariants (special values, relationships between members, lifetime requirements) not clearly expressed by the type and name, they must be commented. 変数の型や変数名だけでは明確に表現できない不変条件(たとえば、特殊な意味を持つ値の存在や、メンバ間の関連性、寿命に関する要件など)がある場合は、それらをコメントとして記述しなければなりません。 However, if the type and name suffice (int num_events_;), no comment is needed. 反対に、int num_events_;のように、型と名前だけで十分説明できているのであれば、コメントは不要です。

In particular, add comments to describe the existence and meaning of sentinel values, such as nullptr or -1, when they are not obvious. 特に、nullptr-1のような値に、番兵などの特殊な意味を持たせている場合で、そのことが明白でないときは、そのような値の存在や意味を説明するコメントを付け足してください。 For example: 以下に例を示します。

private:
 // Used to bounds-check table accesses. -1 means
 // that we don't yet know how many entries the table has.
 int num_total_entries_;
private:
 // テーブルアクセス時の境界チェックに使います。-1 は、
 // まだテーブルにいくつの要素があるかわからないことを意味します。
 int num_total_entries_;

グローバル変数に対するコメント

All global variables should have a comment describing what they are, what they are used for, and (if unclear) why they need to be global. すべてのグローバル変数は、その変数が何を表していて、何のために使われ、そしてなぜグローバルである必要があるのか (明確でない場合) 説明するコメントが必要です。 For example: 以下に例を示します。

// The total number of test cases that we run through in this regression test.
const int kNumTestCases = 6;
// この回帰テストにおけるテストケースの総数
const int kNumTestCases = 6;

実装に対するコメント

In your implementation you should have comments in tricky, non-obvious, interesting, or important parts of your code. 実装のコードの中では、トリッキーな部分や、不明瞭な部分、興味深い部分、重要な部分について、コメントを記述してください。

解説のコメント

Tricky or complicated code blocks should have comments before them. トリッキーあるいは複雑なコードブロックについては、その手前に、それらに関するコメントを記述してください。

関数実引数のコメント

When the meaning of a function argument is nonobvious, consider one of the following remedies: 関数呼び出し時、実引数の意味を捉えにくい場合は、次に述べる対策のいずれかを検討してください。

Consider the following example: 次の例を考えてみましょう。
// What are these arguments?
const DecimalNumber product = CalculateProduct(values, 7, false, nullptr);
// これらの引数の意味は何?
const DecimalNumber product = CalculateProduct(values, 7, false, nullptr);

versus: これに対して、次の例はどうでしょうか。

ProductOptions options;
options.set_precision_decimals(7);
options.set_use_cache(ProductOptions::kDontUseCache);
const DecimalNumber product =
    CalculateProduct(values, options, /*completion_callback=*/nullptr);
ProductOptions options;
options.set_precision_decimals(7);
options.set_use_cache(ProductOptions::kDontUseCache);
const DecimalNumber product =
    CalculateProduct(values, options, /*completion_callback=*/nullptr);

してはならないこと

Do not state the obvious. 明白なことをわざわざ主張してはいけません。 In particular, don't literally describe what code does, unless the behavior is nonobvious to a reader who understands C++ well. C++を十分理解している読者にとってもわかりにくい挙動をするような場合は除きますが、それ以外の場合、特に、コードがしていることを逐一文字通りに説明するようなコメントを書いてはいけません。 Instead, provide higher level comments that describe why the code does what it does, or make the code self describing. そのようなコメントのかわりに、より高い次元の、たとえばそのコードがなぜそれをしているのかをコメントで記述したり、あるいはコード自身にそれを説明させるようにしてください。

Compare this: 以下のコード例を比べてみましょう。
// Find the element in the vector. <-- Bad: obvious!
if (std::find(v.begin(), v.end(), element) != v.end()) {
    Process(element);
}
// vectorの中から要素を検索する。  <-- ダメ。見ればわかる。
    if (std::find(v.begin(), v.end(), element) != v.end()) {
        Process(element);
}
To this: 次のコードはどうでしょうか。
// Process "element" unless it was already processed.
if (std::find(v.begin(), v.end(), element) != v.end()) {
  Process(element);
}
// まだ処理していない要素があれば処理する。
auto iter = std::find(v.begin(), v.end(), element);
if (iter != v.end()) {
  Process(element);
}
Self-describing code doesn't need a comment. さらに、コード自身が自分で自分を説明できていると、コメントをも必要としなくなります。 The comment from the example above would be obvious: 上の例におけるコメントのかわりに、以下の例のようにすると、より明確です。
if (!IsAlreadyProcessed(element)) {
  Process(element);
}

句読点と綴りと文法

Pay attention to punctuation, spelling, and grammar; it is easier to read well-written comments than badly written ones. コメントを書く際には、句読点の使い方、正しい綴り((訳注:日本語の場合は誤変換も))、正しい文法を使うことに注意を払ってください。きちんとしたコメントはそれだけで読みやすいものです。

Comments should be as readable as narrative text, with proper capitalization and punctuation. コメントは、大文字や句読点を適切に用いてふつうの文章として読めるように記述します。 In many cases, complete sentences are more readable than sentence fragments. 多くの場合において、文の断片だけの場合よりも、完全な文にする方が読みやすくなります。 Shorter comments, such as comments at the end of a line of code, can sometimes be less formal, but you should be consistent with your style. 行末コメントなどの短いコメントでは多少形式を崩すこともありますが、極力、一貫したスタイルを保つようにはしてください。

Although it can be frustrating to have a code reviewer point out that you are using a comma when you should be using a semicolon, it is very important that source code maintain a high level of clarity and readability. コードレビュアーからの指摘のうち「セミコロンを使うべきところでカンマを使っている」といったものにはうんざりするかもしれません。しかし、ソースコードの明瞭性や可読性を高いレベルに保つことは、本当に重要なことなのです。 Proper punctuation, spelling, and grammar help with that goal. 適切な句読点、正しい綴り、正しい文法は、このゴールに向かうための手助けをしてくれるでしょう。

TODOコメント

Use TODO comments for code that is temporary, a short-term solution, or good-enough but not perfect. 一時的なコード、暫定対応コード、完璧ではないが現状十分なコード等に対しては、TODOコメントを記述してください。

TODOs should include the string TODO in all caps, followed by the bug ID, name, e-mail address, or other identifier of the person or issue with the best context about the problem referenced by the TODO. TODOコメントは、まず、すべて大文字でTODOと書き、続けて、バグ管理番号や、そのTODOに関して、詳しい人の名前やメールアドレスやその他のID等、あるいは、関連するissueへのリンク等を含めます。

// TODO: bug 12345678 - Remove this after the 2047q4 compatibility window expires.
// TODO: example.com/my-design-doc - Manually fix up this code the next time it's touched.
// TODO(bug 12345678): Update this list after the Foo service is turned down.
// TODO(John): Use a "\*" here for concatenation operator.
// TODO: bug 12345678 - 2047q4の互換性維持期間がおわったら消す
// TODO: example.com/my-design-doc - 次回ここを触るときには直す
// TODO(bug 12345678): Fooサービスを止めたらこのリストを更新する
// TODO(John): ここでは連結演算子として"\*"を使う

If your TODO is of the form "At a future date do something" make sure that you either include a very specific date ("Fix by November 2005") or a very specific event ("Remove this code when all clients can handle XML responses."). もし、そのTODOが「未来のいつ、何をする」という形式になるときは、必ず、具体的な期日(例:「2005年11月までに直す」)や、具体的なイベント(例:「すべてのクライアントがXMLレスポンスを扱えるようになったらこのコードは消す」)を含めるようにしてください。

コードのフォーマット

Coding style and formatting are pretty arbitrary, but a project is much easier to follow if everyone uses the same style. コーディングスタイルやコードフォーマットは好みによるところが大きいものですが、全員が同じスタイルに沿っていれば、プロジェクト全体にも同じルールを適用しやすくなります。 Individuals may not agree with every aspect of the formatting rules, and some of the rules may take some getting used to, but it is important that all project contributors follow the style rules so that they can all read and understand everyone's code easily. ここで定めるフォーマットのルールの中には、各個人にとって賛同しかねるものもあれば、非常に馴染み深いものもあるでしょう。それでも、ここでは、すべてのプロジェクトメンバーが、ある一つのスタイルに沿うことを重要視します。プロジェクト全体でルールを統一することによって、誰もが誰のコードでも読みやすく理解しやすい状態を保つことができるのです。

To help you format code correctly, we've created a settings file for emacs. コードを正しくフォーマットするために、emacsの設定ファイルを用意しています。

行の長さ

Each line of text in your code should be at most 80 characters long. コードの各行の長さは、最大80文字までとします。

We recognize that this rule is controversial, but so much existing code already adheres to it, and we feel that consistency is important. このルールに議論の余地があることは認識していますが、既に多くのコードがこのルールに沿って書かれており、そして、私たちは一貫性が保たれることを重視しています。

Those who favor this rule argue that it is rude to force them to resize their windows and there is no need for anything longer. このルールを推す側の主張は、長いコードによって読者にウィンドウサイズの変更を強制するのは失礼であるし、そもそもコードを横に長くする必要はない、というものです。 Some folks are used to having several code windows side-by-side, and thus don't have room to widen their windows in any case. 人によっては複数のコードウィンドウを横に並べて使っていて、それ以上ウィンドウ幅を広げる余地がないかもしれません。 People set up their work environment assumeing a particular maximum window width, and 80 columns has been the traditional standard. 多くの人が、特定の最大ウィンドウサイズの想定のもとに仕事環境を構築しており、その際の伝統的な標準として横幅80文字が使われてきました。 Why change it? 変える理由があるでしょうか?

Proponents of change argue that a wider line can make code more readable. このルールを変えたがっている側の主張は、行を長くすることでコードがもっと読みやすくなるはずである、というものです。 The 80-column limit is an hidebound throwback to 1960s mainframes; modern equipment has wide screens that can easily show longer lines. 横幅80文字という制限は、1960年代のメインフレームを思い起こさせる干からびたものです。現代的な環境は、もっと長い行を簡単に表示できる広いスクリーンを備えているではありませんか?

80 characters is the maximum. 最大80文字とします。

A line may exceed 80 characters if it is 次に該当する場合は、80文字を超えてもかまいません。

非アスキー文字

Non-ASCII characters should be rare, and must use UTF-8 formatting. 基本的に非アスキー文字は使いません。もし、非アスキー文字を使う場合はUTF-8フォーマットを使います。

You shouldn't hard-code user-facing text in source, even English, so use of non-ASCII characters should be rare. まず前提として、そもそもユーザーの目に触れるようなテキストをソースコード中にハードコーディングしてはいけません。たとえ、英語であってもです。ですから、非アスキー文字をソースコード中で使う機会はほとんどないはずです。 However, in certain cases it is appropriate to include such words in your code. しかし、場合によっては、このような単語をソースコードに含めることが適切であるようなケースもあります。 For example, if your code parses data files from foreign sources, it may be appropriate to hard-code the non-ASCII string(s) used in those data files as delimiters. たとえば、海外から来る何らかのデータファイルを解析するためのコードにおいて、そのデータの区切り文字として使われている非アスキー文字列をソースコードに埋め込むのは妥当なことでしょう。 More commonly, unittest code (which does not need to be localized) might contain non-ASCII strings. もっと一般的な例として、(ローカライズの必要がない)ユニットテストにおいて、非アスキー文字列を含むこともあるでしょう。 In such cases, you should use UTF-8, since that is an encoding understood by most tools able to handle more than just ASCII. このような場合には、エンコーディングとしてUTF-8を使います。UTF-8であれば、ASCII以外も解するほとんどのツールでサポートされています。

Hex encoding is also OK, and encouraged where it enhances readability — for example, "\xEF\xBB\xBF", or, even more simply, "\uFEFF", is the Unicode zero-width no-break space character, which would be invisible if included in the source as straight UTF-8. 16進数によるエンコーディングを使ってもかまいません。特に、そうすることで可読性が高まる場合は積極的に使用してください。たとえば、"\xEF\xBB\xBF"や、より単純に"\uFEFF"は、Unicodeのゼロ幅改行なしスペース文字ですが、これが普通のUTF-8文字としてソースコード中に埋め込まれていたら、ソースコードの中では見えなくなってしまうでしょう。

When possible, avoid the u8 prefix. 可能な限り、u8接頭辞を避けてください。 It has significantly different semantics starting in C++20 than in C++17, producing arrays of char8_t rather than char, and will change again in C++23. C++17以前と比べて、C++20で、そのセマンティクスが大きく変更され、u8接頭辞は、charの配列ではなくchar8_tの配列を生成するようになりました。そして、さらなる変更がC++23で予定されています。

You shouldn't use char16_t and char32_t character types, since they're for non-UTF-8 text. char16_tchar32_tは、UTF-8以外のテキストのためのものであるため、原則として使うことはありません。 For similar reasons you also shouldn't use wchar_t (unless you're writing code that interacts with the Windows API, which uses wchar_t extensively). 同様の理由で、 (Windows APIを使うコードを除き) wchar_tも使いません。

スペースか、タブか

Use only spaces, and indent 2 spaces at a time. スペースだけを使います。インデント1つにつき、スペース2つとします。

We use spaces for indentation. インデントにはスペースを使います。 Do not use tabs in your code. タブは使いません。 You should set your editor to emit spaces when you hit the tab key. タブキーを押したときに、スペースが入力されるようにエディタを設定してください。

関数宣言と関数定義

Return type on the same line as function name, parameters on the same line if they fit. 関数の戻り値の型は、関数名と同じ行に記述します。 引数は、行内に収まる限り、同じ行に記述します。 Wrap parameter lists which do not fit on a single line as you would wrap arguments in a function call. 引数リストが1行に収まらないときは、関数呼び出しと同じ方法で、行を分割します。

Functions look like this: 関数は次のようにします。

ReturnType ClassName::FunctionName(Type par_name1, Type par_name2) {
  DoSomething();
  ...
}

If you have too much text to fit on one line: 1行に収まらないときは、次のようにします。

ReturnType ClassName::ReallyLongFunctionName(Type par_name1, Type par_name2,
                                             Type par_name3) {
  DoSomething();
  ...
}

or if you cannot fit even the first parameter: もし、最初の引数からして同じ行に収まらないのであれば、次のようにします。

ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
    Type par_name1,  // 4 space indent
    Type par_name2,
    Type par_name3) {
  DoSomething();  // 2 space indent
  ...
}
ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
    Type par_name1,  // スペース4個でインデント
    Type par_name2,
    Type par_name3) {
  DoSomething();  // スペース2個でインデント
  ...
}

Some points to note: 次の点に注意してください。

Unused parameters that are obvious from context may be omitted: 次の例のように、引数が使われず、かつ、その意味が文脈から明白な場合は、引数を省略できます。

class Foo {
 public:
  Foo(const Foo&) = delete;
  Foo& operator=(const Foo&) = delete;
};

Unused parameters that might not be obvious should comment out the variable name in the function definition: ただし、使わない引数であっても、その意味が文脈から明白でないときには、省略せずにコメントとして残します。

class Shape {
 public:
  virtual void Rotate(double radians) = 0;
};

class Circle : public Shape {
 public:
  void Rotate(double radians) override;
};

void Circle::Rotate(double /*radians*/) {}
// Bad - if someone wants to implement later, it's not clear what the
// variable means.
void Circle::Rotate(double) {}
// これはダメ。将来、実装を追加するとき、引数の意図がわからなくなってしまう。
void Circle::Rotate(double) {}

Attributes, and macros that expand to attributes, appear at the very beginning of the function declaration or definition, before the return type: 属性や、属性に展開されるマクロは、関数宣言や関数定義の最も先頭、戻り値の型よりも前に書きます。

  ABSL_ATTRIBUTE_NOINLINE void ExpensiveFunction();
  [[nodiscard]] bool IsOk();

ラムダ式

Format parameters and bodies as for any other function, and capture lists like other comma-separated lists. ラムダ式の引数リストと関数本体は、通常の関数と同様にフォーマットします。 キャプチャリストは、他のカンマ区切りのリストと同様にフォーマットします。

For by-reference captures, do not leave a space between the ampersand (&) and the variable name. 参照キャプチャについて、アンパサンド(&)と変数名の間には、スペースを入れません。

int x = 0;
auto x_plus_n = [&x](int n) -> int { return x + n; }

Short lambdas may be written inline as function arguments. 短いラムダは、関数の実引数として直接その場に書いてもかまいません。

absl::flat_hash_set<int> to_remove = {7, 8, 9};
std::vector<int> digits = {3, 9, 1, 8, 4, 7, 1};
digits.erase(std::remove_if(digits.begin(), digits.end(), [&to_remove](int i) {
               return to_remove.contains(i);
             }),
             digits.end());

浮動小数点リテラル

Floating-point literals should always have a radix point, with digits on both sides, even if they use exponential notation. 浮動小数点リテラルでは、指数表記を使用する場合であっても、常に小数点を書き、常に小数点の両側に1桁以上ずつ数字を書きます。 Readability is improved if all floating-point literals take this familiar form, as this helps ensure that they are not mistaken for integer literals, and that the E/e of the exponential notation is not mistaken for a hexadecimal digit. すべての浮動小数点リテラルの見た目が、この見慣れた形に統一されていれば、それらを整数リテラルと取り違えたり、指数表記のEeを16進数に見間違えたりすることもなくなり、コードの可読性の向上に繋がります。 It is fine to initialize a floating-point variable with an integer literal (assuming the variable type can exactly represent that integer), but note that a number in exponential notation is never an integer literal. 浮動小数点変数を整数リテラルで初期化してもかまいません (ただし、その整数値を正確に表せる場合に限ります)。一方で、指数表記された数値は決して整数リテラルにはなりませんので注意してください。

float f = 1.f;
long double ld = -.5L;
double d = 1248e6;
float f = 1.0f;
float f2 = 1;   // Also OK
long double ld = -0.5L;
double d = 1248.0e6;
float f = 1.0f;
float f2 = 1;   // これもOK
long double ld = -0.5L;
double d = 1248.0e6;

関数呼び出し

Either write the call all on a single line, wrap the arguments at the parenthesis, or start the arguments on a new line indented by four spaces and continue at that 4 space indent. 関数呼び出しは、全体を1行で書くか、引数リストを途中改行して丸括弧(のところで整列させるか、4つのスペースでインデントした新しい行から引数を書きはじめるかのいずれかとします。 In the absence of other considerations, use the minimum number of lines, including placing multiple arguments on each line where appropriate. 他に特別な理由がない限り、各行に複数の引数をまとめて、可能な限り少ない行数で記述します。

Function calls have the following format: 関数呼び出しは、次のォーマットに従います。

bool result = DoSomething(argument1, argument2, argument3);

If the arguments do not all fit on one line, they should be broken up onto multiple lines, with each subsequent line aligned with the first argument. もし、すべての引数が1行に収まらない場合、それらを複数の行に分割します。その際、後続の行は、最初の引数に揃えるようにします。 Do not add spaces after the open paren or before the close paren: 開き丸括弧(の後や、閉じ丸括弧)の前にスペースを入れてはいけません。

bool result = DoSomething(averyveryveryverylongargument1,
                          argument2, argument3);

Arguments may optionally all be placed on subsequent lines with a four space indent: 引数は、それらをすべて、スペース4つでインデントされた後続の行に記述してもかまいません。

if (...) {
  ...
  ...
  if (...) {
    bool result = DoSomething(
        argument1, argument2,  // 4 space indent
        argument3, argument4);
    ...
  }
if (...) {
  ...
  ...
  if (...) {
    bool result = DoSomething(
        argument1, argument2,  // スペース4つでインデント
        argument3, argument4);
    ...
  }

Put multiple arguments on a single line to reduce the number of lines necessary for calling a function unless there is a specific readability problem. 可読性の妨げとならない限り、複数の引数を1つの行にまとめ、関数呼び出しに要する行数を減らしてください。 Some find that formatting with strictly one argument on each line is more readable and simplifies editing of the arguments. 人によっては、厳密に1行に1つずつ引数を置く形式の方が読みやすく、編集もしやすいと考えるかもしれません。 However, we prioritize for the reader over the ease of editing arguments, and most readability problems are better addressed with the following techniques. しかし、私たちは、編集のしやすよりも、読者にとっての読みやすさを優先します。また、読みやすさに関する問題のほとんどは、以下で述べるテクニックによって解決することができます。

If having multiple arguments in a single line decreases readability due to the complexity or confusing nature of the expressions that make up some arguments, try creating variables that capture those arguments in a descriptive name: 引数が複雑な式から構成されていて、1行にそれらをまとめると読みにくくなるという場合には、次のように、それらの引数のための一時変数を作って、適切な名前を与えてください。

int my_heuristic = scores[x] * y + bases[x];
bool result = DoSomething(my_heuristic, x, y, z);

Or put the confusing argument on its own line with an explanatory comment: あるいは、次のように、意味のわかりにくい引数を個別の行にわけて、説明のためのコメントを記述してください。

bool result = DoSomething(scores[x] * y + bases[x],  // Score heuristic.
                          x, y, z);
bool result = DoSomething(scores[x] * y + bases[x],  // ヒューリスティックなスコア
                          x, y, z);

If there is still a case where one argument is significantly more readable on its own line, then put it on its own line. それでもまだ、引数を1行に1つだけにした方がはるかに読みやすいという場合には、いよいよそのようにしましょう。 The decision should be specific to the argument which is made more readable rather than a general policy. 全体的なポリシーを守るよりも、それらの引数が読みやすくなる方を選んでください。

Sometimes arguments form a structure that is important for readability. 時折、関数引数は、次の例のように、可読性の面で重要な、何らかの構造を成すことがあります。 In those cases, feel free to format the arguments according to that structure: このような場合には、その構造に沿って自由に引数を配置してかまいません。

// Transform the widget by a 3x3 matrix.
my_widget.Transform(x1, x2, x3,
                    y1, y2, y3,
                    z1, z2, z3);
// ウィジェットを3x3行列で変形する
my_widget.Transform(x1, x2, x3,
                    y1, y2, y3,
                    z1, z2, z3);

波括弧による初期化子リスト

Format a braced initializer list exactly like you would format a function call in its place. 波括弧による初期化子リストは、関数呼び出しと同じようにフォーマットします。

If the braced list follows a name (e.g., a type or variable name), format as if the {} were the parentheses of a function call with that name. 波括弧のリストが型名や変数名の直後に続く場合は、それらの波括弧{}を関数呼び出しのときの丸括弧()に見立てて、その引数と同じようにフォーマットします。 If there is no name, assume a zero-length name. 名前がない場合は、0文字の名前があると考えてフォーマットします。

// Examples of braced init list on a single line.
return {foo, bar};
functioncall({foo, bar});
std::pair<int, int> p{foo, bar};

// When you have to wrap.
SomeFunction(
    {"assume a zero-length name before {"},
    some_other_function_parameter);
SomeType variable{
    some, other, values,
    {"assume a zero-length name before {"},
    SomeOtherType{
        "Very long string requiring the surrounding breaks.",
        some, other, values},
    SomeOtherType{"Slightly shorter string",
                  some, other, values}};
SomeType variable{
    "This is too long to fit all in one line"};
MyType m = {  // Here, you could also break before {.
    superlongvariablename1,
    superlongvariablename2,
    {short, interior, list},
    {interiorwrappinglist,
     interiorwrappinglist2}};
// 1行の初期化子リストの例
return {foo, bar};
functioncall({foo, bar});
std::pair<int, int> p{foo, bar};

// 複数行にする場合
SomeFunction(
    {"{の前に、0文字の名前があるかのように扱います"},
    some_other_function_parameter);
SomeType variable{
    some, other, values,
    {"{の前に、0文字の名前があるかのように扱います"},
    SomeOtherType{
        "それの前後に改行を要するようなとてもとても長い文字列。",
        some, other, values},
    SomeOtherType{"それよりは少し短めの文字列",
                  some, other, values}};
SomeType variable{
    "全体を1行に納めるには少しばかり長すぎる文字列"};
MyType m = {  // {の前で改行してもかまいません
    superlongvariablename1,  // 超長い変数名
    superlongvariablename2,
    {short, interior, list}, // 短いリスト
    {interiorwrappinglist,   // 改行を要するリスト
     interiorwrappinglist2}};

ループと条件分岐

At a high level, looping or branching statements consist of the following components: おおまかに、ループや分岐のための文は、次のような部品から成り立っていると言えます。

For these statements:これらの文について:

if (condition) {                   // Good - no spaces inside parentheses, space before brace.
  DoOneThing();                    // Good - two-space indent.
  DoAnotherThing();
} else if (int a = f(); a != 3) {  // Good - closing brace on new line, else on same line.
  DoAThirdThing(a);
} else {
  DoNothing();
}

// Good - the same rules apply to loops.
while (condition) {
  RepeatAThing();
}

// Good - the same rules apply to loops.
do {
  RepeatAThing();
} while (condition);

// Good - the same rules apply to loops.
for (int i = 0; i < 10; ++i) {
  RepeatAThing();
}
if (condition) {                   // 良い例。丸括弧内はスペースなし、開き波括弧の前にスペースあり
  DoOneThing();                    // 良い例。スペース2つでインデント
  DoAnotherThing();
} else if (int a = f(); a != 3) {  // 良い例。閉じ波括弧の前で改行、elseは同一行内
  DoAThirdThing(a);
} else {
  DoNothing();
}

// 良い例。ループ文にも同じルールを適用します。
while (condition) {
  RepeatAThing();
}

// 良い例。ループ文にも同じルールを適用します。
do {
  RepeatAThing();
} while (condition);

// 良い例。ループ文にも同じルールを適用します。
for (int i = 0; i < 10; ++i) {
  RepeatAThing();
}
if(condition) {}                   // Bad - space missing after `if`.
else if ( condition ) {}           // Bad - space between the parentheses and the condition.
else if (condition){}              // Bad - space missing before `{`.
else if(condition){}               // Bad - multiple spaces missing.

for (int a = f();a == 10) {}       // Bad - space missing after the semicolon.

// Bad - `if ... else` statement does not have braces everywhere.
if (condition)
  foo;
else {
  bar;
}

// Bad - `if` statement too long to omit braces.
if (condition)
  // Comment
  DoSomething();

// Bad - `if` statement too long to omit braces.
if (condition1 &&
    condition2)
  DoSomething();
if(condition) {}                   // ダメ。ifの後にスペースがない。
else if ( condition ) {}           // ダメ。括弧と条件の間にスペースがある。
else if (condition){}              // ダメ。{の前にスペースがない。
else if(condition){}               // ダメ。諸々スペースがない

for (int a = f();a == 10) {}       // ダメ。セミコロンの後にスペースがない。

// ダメ。`if ... else`文のすべての場所に{}がない
if (condition)
  foo;
else {
  bar;
}

// ダメ。{}を省略するにはif文が長すぎる
if (condition)
  // 何かしらコメント何かしらコメント何かしらコメント
  DoSomething();

// ダメ。{}を省略するにはif文が長すぎる
if (condition1 &&
    condition2)
  DoSomething();

For historical reasons, we allow one exception to the above rules: the curly braces for the controlled statement or the line breaks inside the curly braces may be omitted if as a result the entire statement appears on either a single line (in which case there is a space between the closing parenthesis and the controlled statement) or on two lines (in which case there is a line break after the closing parenthesis and there are no braces). 歴史的経緯により、このルールについては、文全体が1行か2行におさまる場合の例外を設けています。この条件に該当する場合は、制御対象文を囲む波括弧自体や、あるいは、波括弧の内側の改行を省略しても許容するものとします。 全体を1行とする場合は、条件の閉じ括弧)と制御対象文との間に1つスペースをあけます。 全体を2行とする場合は、条件の閉じ括弧)の直後で改行し、波括弧を削ります。

// OK - fits on one line.
if (x == kFoo) { return new Foo(); }

// OK - braces are optional in this case.
if (x == kFoo) return new Foo();

// OK - condition fits on one line, body fits on another.
if (x == kBar)
  Bar(arg1, arg2, arg3);
// 許容される例。1行におさまっている。
if (x == kFoo) { return new Foo(); }

// 許容される例。このケースでは{}を省略できます。
if (x == kFoo) return new Foo();

// 許容される例。条件が1行に、制御対象文が次の1行におさまっている。
if (x == kBar)
  Bar(arg1, arg2, arg3);

This exception does not apply to multi-keyword statements like if ... else or do ... while. ただし、この例外ルールは、if...elseや、do...while等の、複数のキーワードからなる構文には適用しません。これらの場合は常にすべての波括弧が必要です。

// Bad - `if ... else` statement is missing braces.
if (x) DoThis();
else DoThat();

// Bad - `do ... while` statement is missing braces.
do DoThis();
while (x);
// ダメ。`if ... else`の形においては{}は省略不可
if (x) DoThis();
else DoThat();

// ダメ。`do ... while`の形においては{}は省略不可
do DoThis();
while (x);

Use this style only when the statement is brief, and consider that loops and branching statements with complex conditions or controlled statements may be more readable with curly braces. この例外的なスタイルは、文が短く簡潔である場合にのみ適用してください。 ループ文や条件分岐文が、複雑な条件あるいは複雑な制御対象文を持つときは、通常通り波括弧を用いて読みやすくできないか検討してください。 Some projects require curly braces always. また、プロジェクトによっては、この例外ルールを認めず、常に波括弧を必須とするよう定めていることもありますので注意してください。

case blocks in switch statements can have curly braces or not, depending on your preference. switch文のcaseブロックでは、波括弧を書いても書かなくてもかまいません。 If you do include curly braces, they should be placed as shown below. もし、波括弧を書く場合は、次のようにしてください。

switch (var) {
  case 0: {  // 2 space indent
    Foo();   // 4 space indent
    break;
  }
  default: {
    Bar();
  }
}
switch (var) {
  case 0: {  // スペース2つでインデント
    Foo();   // スペース4つでインデント
    break;
  }
  default: {
    Bar();
  }
}

Empty loop bodies should use either an empty pair of braces or continue with no braces, rather than a single semicolon. ループの本体が空になる場合は、波括弧による空のブロックとするか、波括弧なしでcontinueを使います。セミコロンだけを書いてはいけません。

while (condition) {}  // Good - `{}` indicates no logic.
while (condition) {
  // Comments are okay, too
}
while (condition) continue;  // Good - `continue` indicates no logic.
while (condition) {}  // 良い例。`{}`によって、ロジックがないことを明示している。
while (condition) {
  // コメントだけを書いてもよい
}
while (condition) continue;  // 良い例。 `continue` によって、ロジックがないことを明示している。
while (condition);  // Bad - looks like part of `do-while` loop.
while (condition);  // ダメ。do-whileループの一部にも見える。

ポインタと参照の表現

No spaces around period or arrow. ドット演算子やアロー演算子の周りにスペースは使いません。 Pointer operators do not have trailing spaces. ポインタ演算子の後にはスペースを使いません。

The following are examples of correctly-formatted pointer and reference expressions: ポインタおよび参照に関する正しいフォーマットの例を以下に示します。

x = *p;
p = &x;
x = r.y;
x = r->y;

Note that: 以下のことに注意してください。

When referring to a pointer or reference (variable declarations or definitions, arguments, return types, template parameters, etc), you may place the space before or after the asterisk/ampersand. ポインタ型や参照型の宣言 (変数、引数、戻り値型、テンプレート引数など) では、アスタリスク(*)やアンパサンド(&)を型名と変数名のどちらにつけてもかまいません。 In the trailing-space style, the space is elided in some cases (template parameters, etc). 型名につける (後ろにスペースを置く) スタイルの場合、テンプレート引数などの型名のみを要する箇所ではスペースを省きます。

// These are fine, space preceding.
char *c;
const std::string &str;
int *GetPointer();
std::vector<char *>

// These are fine, space following (or elided).
char* c;
const std::string& str;
int* GetPointer();
std::vector<char*>  // Note no space between '*' and '>'
// これらはOK。スペースが先。
char *c;
const std::string &str;
int *GetPointer();
std::vector<char *>

// これらもOK。スペースが後(か省略)。
char* c;
const std::string& str;
int* GetPointer();
std::vector<char*>  // '*' と '>'の間にスペースなし

You should do this consistently within a single file. 1つのファイル内では一貫したスタイルを保つようにしてください。 When modifying an existing file, use the style in that file. 既存のファイルを変更するときは、そのファイル内で使われているスタイルにあわせてください。

It is allowed (if unusual) to declare multiple variables in the same declaration, but it is disallowed if any of those have pointer or reference decorations. 変数宣言において、通常変数は、1つの宣言で複数の変数をまとめて宣言することは問題ありません。しかし、その宣言の中に1つでもポインタや参照の宣言を含む場合は同時に宣言してはいけません。 Such declarations are easily misread. そのような宣言は簡単に誤解してしまうためです。
// Fine if helpful for readability.
int x, y;
// 可読性が高まる場合はOK
int x, y;
int x, *y;  // Disallowed - no & or * in multiple declaration
char * c;  // Bad - spaces on both sides of *
const std::string & str;  // Bad - spaces on both sides of &
int x, *y;  // 不可。&や*が複数宣言の中に含められている。
char * c;  // ダメ。*の前後両方にスペースがある。
const std::string & str;  // ダメ。&の前後両方にスペースがある。

ブール式

When you have a boolean expression that is longer than the standard line length, be consistent in how you break up the lines. ブール式が標準の行の長さを超えるような場合、行の区切り方について一貫性を保ってください。

In this example, the logical AND operator is always at the end of the lines: たとえば、次のコード例では、論理積演算子(&&)を常に行末に配置しています。

if (this_one_thing > this_other_thing &&
    a_third_thing == a_fourth_thing &&
    yet_another && last_one) {
  ...
}
if (this_one_thing > this_other_thing &&
    a_third_thing == a_fourth_thing &&
    yet_another && last_one) {
  ...
}

Note that when the code wraps in this example, both of the && logical AND operators are at the end of the line. この例において、両方の論理積演算子(&&)が、いずれも行末にあることに注目してください。 This is more common in Google code, though wrapping all operators at the beginning of the line is also allowed. Googleのコードにおいては、このように演算子を行末に置く形がよく使われますが、演算子を次行の頭に置くスタイルでもかまいません。 Feel free to insert extra parentheses judiciously because they can be very helpful in increasing readability when used appropriately, but be careful about overuse. また、これらの式において、追加の丸括弧を適切に挿入することで、大幅に可読性を高められる場合があります。そのような丸括弧は自由に挿入してかまいません。ただし、使いすぎには気をつけてください。 Also note that you should always use the punctuation operators, such as && and ~, rather than the word operators, such as and and compl. なお、これらの論理演算を行う際は、andcomplのような単語による演算子ではなく、常に&&~のような記号による演算子を使用してください。

戻り値

Do not needlessly surround the return expression with parentheses. return文の式を不要な丸括弧で囲んではいけません。

Use parentheses in return expr; only where you would use them in x = expr;. return expr;に丸括弧を使うのは、式がx = expr;の形をしている場合のみです。

return result;                  // No parentheses in the simple case.
// Parentheses OK to make a complex expression more readable.
return (some_long_condition &&
        another_condition);
return result;                  // 単純なものには丸括弧を使いません。

// これはOK。複雑な式を読みやすくするために、丸括弧を使っています。
return (some_long_condition &&
        another_condition);
return (value);                // You wouldn't write var = (value);
return(result);                // return is not a function!
return (value);                // var = (value);とは書かないでしょう。
return(result);                // returnは関数ではありません!

変数と配列の初期化

You may choose between =, (), and {}; the following are all correct: =(){}のうち、いずれを使用してもかまいません。次の例はすべてOKです。

int x = 3;
int x(3);
int x{3};
std::string name = "Some Name";
std::string name("Some Name");
std::string name{"Some Name"};
int x = 3;
int x(3);
int x{3};
std::string name = "Some Name";
std::string name("Some Name");
std::string name{"Some Name"};

Be careful when using a braced initialization list {...} on a type with an std::initializer_list constructor. ただし、波括弧による初期化子リスト{...}については、型がstd::initializer_listを引数にとるコンストラクタを持つ場合に注意が必要です。 A nonempty braced-init-list prefers the std::initializer_list constructor whenever possible. 空でない波括弧初期化リストは、可能な限りstd::initializer_listのコンストラクタを呼び出そうとします。 Note that empty braces {} are special, and will call a default constructor if available. ただし、リストが空{}のときだけは特別で、デフォルトコンストラクタが優先的に呼び出されます。 To force the non-std::initializer_list constructor, use parentheses instead of braces. std::initializer_list以外のコンストラクタを呼び出すことを強制するためには、波括弧{...}ではなく丸括弧(...)による初期化を行ってください。

std::vector<int> v(100, 1);  // A vector containing 100 items: All 1s.
std::vector<int> v{100, 1};  // A vector containing 2 items: 100 and 1.
std::vector<int> v(100, 1);  // 中身は「1」が100個。
std::vector<int> v{100, 1};  // 中身は「100」と「1」の2個。

Also, the brace form prevents narrowing of integral types. また、整数型の初期化に波括弧を用いると、小さい型への変換を防ぐことができます。 This can prevent some types of programming errors. これによって、ある種のプログラミング上のミスを防ぐことができます。

int pi(3.14);  // OK -- pi == 3.
int pi{3.14};  // Compile error: narrowing conversion.
int pi(3.14);  // OK?  コンパイルが通る。 pi == 3 になる。
int pi{3.14};  // コンパイルエラー: より小さい型への変換

プリプロセッサディレクティブ

The hash mark that starts a preprocessor directive should always be at the beginning of the line. プリプロセッサディレクティブのための#は、常に行頭に置きます。

Even when preprocessor directives are within the body of indented code, the directives should start at the beginning of the line. たとえプリプロセッサディレクティブをインデントされているコードの中に書く場合であっても、ディレクティブは行の頭から記述します。

// Good - directives at beginning of line
  if (lopsided_score) {
#if DISASTER_PENDING      // Correct -- Starts at beginning of line
    DropEverything();
# if NOTIFY               // OK but not required -- Spaces after #
    NotifyClient();
# endif
#endif
    BackToNormal();
  }
// OK。プリプロセッサが行の頭にある。
  if (lopsided_score) {
#if DISASTER_PENDING      // 正しい。行頭から始める。
    DropEverything();
# if NOTIFY               // #の後ならスペースもOK(必須ではない)。
    NotifyClient();
# endif
#endif
    BackToNormal();
  }
// Bad - indented directives
  if (lopsided_score) {
    #if DISASTER_PENDING  // Wrong!  The "#if" should be at beginning of line
    DropEverything();
    #endif                // Wrong!  Do not indent "#endif"
    BackToNormal();
  }
// ダメ。ディレクティブがインデントされている。
  if (lopsided_score) {
    #if DISASTER_PENDING  // 間違い! "#if"は行頭になくてはならない。
    DropEverything();
    #endif                // 間違い! #endifをインデントしてはダメ。
    BackToNormal();
  }

クラスのフォーマット

Sections in public, protected and private order, each indented one space. クラス内のセクションはpublicprotectedprivateの順で並べ、これらのキーワードはスペース1文字でインデントします。

The basic format for a class definition (lacking the comments, seeClass Comments for a discussion of what comments are needed) is: クラス定義の基本的なフォーマットを以下に示します(ただし、コメントは省いています。コメントについては、クラスのコメントで議論しています)

class MyClass : public OtherClass {
 public:      // Note the 1 space indent!
  MyClass();  // Regular 2 space indent.
  explicit MyClass(int var);
  ~MyClass() {}

  void SomeFunction();
  void SomeFunctionThatDoesNothing() {
  }

  void set_some_var(int var) { some_var_ = var; }
  int some_var() const { return some_var_; }

 private:
  bool SomeInternalFunction();

  int some_var_;
  int some_other_var_;
};
class MyClass : public OtherClass {
 public:      // 注意: スペース1つでインデント!
  MyClass();  // いつもの。スペース2つでインデント
  explicit MyClass(int var);
  ~MyClass() {}

  void SomeFunction();
  void SomeFunctionThatDoesNothing() {
  }

  void set_some_var(int var) { some_var_ = var; }
  int some_var() const { return some_var_; }

 private:
  bool SomeInternalFunction();

  int some_var_;
  int some_other_var_;
};

Things to note: 次の点に注意してください。

コンストラクタの初期化子リスト

Constructor initializer lists can be all on one line or with subsequent lines indented four spaces. コンストラクタの初期化子リストは、すべて同じ行に収めるか、あるいは、1行に収まらない場合は、続く行をスペース4つでインデントします。

The acceptable formats for initializer lists are: 初期化子リストの正しい例を以下に示します。

// When everything fits on one line:
MyClass::MyClass(int var) : some_var_(var) {
  DoSomething();
}

// If the signature and initializer list are not all on one line,
// you must wrap before the colon and indent 4 spaces:
MyClass::MyClass(int var)
    : some_var_(var), some_other_var_(var + 1) {
  DoSomething();
}

// When the list spans multiple lines, put each member on its own line
// and align them:
MyClass::MyClass(int var)
    : some_var_(var),             // 4 space indent
      some_other_var_(var + 1) {  // lined up
  DoSomething();
}

// As with any other code block, the close curly can be on the same
// line as the open curly, if it fits.
MyClass::MyClass(int var)
    : some_var_(var) {}
// 1行にすべて収まるとき
MyClass::MyClass(int var) : some_var_(var) {
  DoSomething();
}

// 関数シグネチャと初期化子リストの全体が1行に収まらない場合は、
// コロンの前で行を区切り、スペース4つでインデントします。
MyClass::MyClass(int var)
    : some_var_(var), some_other_var_(var + 1) {
  DoSomething();
}

// 初期化子リストが複数行にまたがる場合は、
// 1行に1つずつメンバ初期化子を書き、整列させます。
MyClass::MyClass(int var)
    : some_var_(var),             // スペース4つでインデント。
      some_other_var_(var + 1) {  // 整列させます
  DoSomething();
}

// 他のコードブロックと同様ですが、1行に収まるのであれば、
// 開き波括弧`{`と、閉じ波括弧`}`を、同じ行においてもかまいません。
MyClass::MyClass(int var)
    : some_var_(var) {}

名前空間のフォーマット

The contents of namespaces are not indented. 名前空間の内容はインデントしません。

Namespaces do not add an extra level of indentation. 名前空間ではインデントを足しません。 For example, use: たとえば、次のようにします。

namespace {

void foo() {  // Correct.  No extra indentation within namespace.
  ...
}

}  // namespace
namespace {

void foo() {  // 正しい。名前空間はインデントを追加しない。
  ...
}

}  // namespace

Do not indent within a namespace: 名前空間の中ではインデントしてはいけません。

namespace {

  // Wrong!  Indented when it should not be.
  void foo() {
    ...
  }

}  // namespace
namespace {

  // 間違い! インデントしてはだめ。
  void foo() {
    ...
  }

}  // namespace

When declaring nested namespaces, put each namespace on its own line. 名前空間の宣言をネストするときは、1行に1つずつにします。

namespace foo {
namespace bar {
namespace foo {
namespace bar {

水平方向の空白

Use of horizontal whitespace depends on location. 水平方向の空白は場所に応じて使いわけます。 Never put trailing whitespace at the end of a line. 行末に空白をおいてはいけません。

全般

int i = 0;  // Two spaces before end-of-line comments.

void f(bool b) {  // Open braces should always have a space before them.
  ...
int i = 0;  // Semicolons usually have no space before them.
// Spaces inside braces for braced-init-list are optional.  If you use them,
// put them on both sides!
int x[] = { 0 };
int x[] = {0};

// Spaces around the colon in inheritance and initializer lists.
class Foo : public Bar {
 public:
  // For inline function implementations, put spaces between the braces
  // and the implementation itself.
  Foo(int b) : Bar(), baz_(b) {}  // No spaces inside empty braces.
  void Reset() { baz_ = 0; }  // Spaces separating braces from implementation.
  ...
int i = 0;  // 行末コメントの前にはスペース2つ。

void f(bool b) {  // 開き波括弧{の前には常にスペースを置く。
  ...

int i = 0;  // 通常は、セミコロンの前にスペースを置かない。

// 波括弧初期化子リスト{}の内側のスペースは任意。
// ただし、スペースを置く場合は、必ず左右の両方に置くこと。
int x[] = { 0 };
int x[] = {0};

// 継承や初期化子リストのコロンの前後にはスペースを置く。
class Foo : public Bar {
 public:
  // インライン関数の実装において、波括弧と実装の間にはスペースを置く。
  Foo(int b) : Bar(), baz_(b) {}  // 空の実装にはスペースを置かない。
  void Reset() { baz_ = 0; }  // 波括弧と実装との間にはスペースを置く。
  ...

Adding trailing whitespace can cause extra work for others editing the same file, when they merge, as can removing existing trailing whitespace. 行末にスペースを追加してしまうと、同じファイルで作業している他の人がファイルをマージする際に、これらのスペースを取り除く余計な仕事を発生させてしまいます。 So: Don't introduce trailing whitespace. ですから、行末にスペースを入れてはいけません。 Remove it if you're already changing that line, or do it in a separate clean-up operation (preferably when no-one else is working on the file). 既存の行末のスペースは、そのような行を編集したタイミングで取り除くか、あるいは、別途、コードを整理するタイミングを設けて、まとめて取り除くようにしてください (この場合は、そのファイルを誰も編集していないときに行うのがよいでしょう)。

ループと条件式

if (b) {          // Space after the keyword in conditions and loops.
} else {          // Spaces around else.
}
while (test) {}   // There is usually no space inside parentheses.
switch (i) {
for (int i = 0; i < 5; ++i) {
// Loops and conditions may have spaces inside parentheses, but this
// is rare.  Be consistent.
switch ( i ) {
if ( test ) {
for ( int i = 0; i < 5; ++i ) {
// For loops always have a space after the semicolon.  They may have a space
// before the semicolon, but this is rare.
for ( ; i < 5 ; ++i) {
  ...

// Range-based for loops always have a space before and after the colon.
for (auto x : counts) {
  ...
}
switch (i) {
  case 1:         // No space before colon in a switch case.
    ...
  case 2: break;  // Use a space after a colon if there's code after it.
if (b) {          // 条件文キーワードやループキーワードは直後にスペースを置きます。
} else {          // elseは前後にスペースを置きます。
}
while (test) {}   // 通常、丸括弧の内側にはスペースを置きません。
switch (i) {
for (int i = 0; i < 5; ++i) {

// ループと条件式の丸括弧の内側には、スペースを置いてもかまいませんが、
// そのようなケースはレアケースです。周りとの一貫性を保ってください。
switch ( i ) {
if ( test ) {
for ( int i = 0; i < 5; ++i ) {

// ループでは、常にセミコロンの後にスペースを置きます。
// セミコロンの前にもスペースを置いてもかまいませんが、レアケースです。
for ( ; i < 5 ; ++i) {
  ...

// 範囲for文(range-based for)では、常にコロンの前後にスペースを置きます。
for (auto x : counts) {
  ...
}
switch (i) {
  case 1:         // caseのコロンの前にはスペースを置きません。
    ...
  case 2: break;  // コロンの後にコードが続く場合は、その前にスペースを置きます。

演算子

// Assignment operators always have spaces around them.
x = 0;

// Other binary operators usually have spaces around them, but it's
// OK to remove spaces around factors.  Parentheses should have no
// internal padding.
v = w * x + y / z;
v = w*x + y/z;
v = w * (x + z);

// No spaces separating unary operators and their arguments.
x = -5;
++x;
if (x && !y)
  ...
// 代入演算子の前後には常にスペースを置きます。
x = 0;

// その他の二項演算子の前後には、通常はスペースを置きます。
// ただし項の前後のスペースは、適宜削除してもかまいません。
// 丸括弧を使う場合は、その内側にはスペースを置きません。
v = w * x + y / z;
v = w*x + y/z;
v = w * (x + z);

// 単項演算子においては、その引数との間にスペースは置きません。
x = -5;
++x;
if (x && !y)
  ...

テンプレートとキャスト

// No spaces inside the angle brackets (< and >), before
// <, or between >( in a cast
std::vector<std::string> x;
y = static_cast<char*>(x);

// Spaces between type and pointer are OK, but be consistent.
std::vector<char *> x;
// 山括弧(<>)の内側にはスペースを置きません。
// キャストにおける<の前や、
// >(との間にもスペースを置きません。
std::vector<std::string> x;
y = static_cast<char*>(x);

// ポインタと型名の間のスペースはOKですが、周囲との一貫性を保ってください。
std::vector<char *> x;

垂直方向の空白

Minimize use of vertical whitespace. 垂直方向の空白は最小限にします。

This is more a principle than a rule: don't use blank lines when you don't have to. これはルールというよりは原則になりますが、コード内に不要な空行を残してはいけません。 In particular, don't put more than one or two blank lines between functions, resist starting functions with a blank line, don't end functions with a blank line, and be sparing with your use of blank lines. 特に、関数と関数との間の空行は多くとも2行までとし、関数を空行で始めたり終わらせたりせず、関数の中でも空行を使いすぎないようにしましょう。 A blank line within a block of code serves like a paragraph break in prose: visually separating two thoughts. コードブロック中の空行には、通常の散文における段落を区切るような、2つの思考や概念を視覚的に分離する効果があります。

The basic principle is: The more code that fits on one screen, the easier it is to follow and understand the control flow of the program. 基本的な原則は「1画面に収まるコードが多ければ多いほど、プログラムの流れが追いやすく、理解しやすくなる」というものです。 Use whitespace purposefully to provide separation in that flow. 空白は、フローを分離する目的をもって、意図的に使いましょう。

Some rules of thumb to help when blank lines may be useful: 空行が有効に働くのはどのような場合か、経験則として、次のルールを参考にしてみてください。

ルールの例外

The coding conventions described above are mandatory. ここまでに説明したコーディング規約はすべて必須のものです。 However, like all good rules, these sometimes have exceptions, which we discuss here. しかし、すべての良いルールがそうであるように、これらのルールにも例外があります。ここでは、それらの例外的な事項について議論します。

ルールに沿っていない既存のコード

You may diverge from the rules when dealing with code that does not conform to this style guide. このスタイルガイドのルールに準拠しないコードを取り扱う際には、このスタイルガイドのルールから外れてもかまいません。

If you find yourself modifying code that was written to specifications other than those presented by this guide, you may have to diverge from these rules in order to stay consistent with the local conventions in that code. このガイドで示されている仕様とは異なる仕様に沿って書かれたコードを編集する場合には、そのコードが従うコーディング規約との一貫性を保つために、このガイドのルールから外れなければならないかもしれません。 If you are in doubt about how to do this, ask the original author or the person currently responsible for the code. もし、これについてどうすべきか迷ったときは、コードの原著者や現在の責任者と相談してください。 Remember that consistency includes local consistency, too. 一貫性」には、このような局所的な一貫性を保つことも含まれています。そのことを忘れないでください。

Windowsのコード

Windows programmers have developed their own set of coding conventions, mainly derived from the conventions in Windows headers and other Microsoft code. Windowsプログラマーの間では、独自のコーディング規約が開発されてきました。これらは主にWindowsのヘッダーファイルや、その他のMicrosoftのコードが従っているコーディング規約から派生してきたものです。 We want to make it easy for anyone to understand your code, so we have a single set of guidelines for everyone writing C++ on any platform. 私たちは、コードが誰にとっても簡単に理解できるようになることを望んでいるため、プラットフォームに依存しない、すべてのC++を書く人に向けた、唯一のガイドラインを用意しています。

It is worth reiterating a few of the guidelines that you might forget if you are used to the prevalent Windows style: 一般的なWindowsスタイルに慣れているプログラマーにとって忘れてしまいがちなルールについて、ここでおさらいしておきましょう。

However, there are just a few rules that we occasionally need to break on Windows: また、Windowsにおいては、いくつかのルールについて、破らざるをえない場合があります。そのようなルールについて以下に説明します。