# Anonymous Namespace を使おう anonymous namespace とは`.cc`ファイルの中などで使う名前がついていない名前空間。 ```cpp= namespace { constexpr base::TimeDelta kDailyLaunchModeTimeDelta = base::Minutes(30); base::FilePath LacrosLogPath() { return LacrosLogDirectory().Append("lacros.log"); } } // namespace int main() { timer_.Start(FROM_HERE, kDailyLaunchModeTimeDelta, this, &OnDailyLaunchModeTimer); auto log = LacrosLogPath(); } ``` `namespace`とだけ書いて名前を書かないとanonymous namespace。 この中で関数や変数を宣言することができ、その場合`::`をつけずそのまま親namespaseから呼ぶことができる。 一方で他のファイルからは参照できないようになっている。 どんなときにAnonymous Namespaceを使うとよいか?を確認する。 ## そもそもなぜ外のファイルから見えない? 仕様上そうだからと言ってしまえばおしまいだが、ちょっと周辺知識を集めてみる。 ファイル内外から参照できるシンボルと、ファイル内からしか参照できないシンボルがある。 前者は外部リンケージ、後者は内部リンケージと名付けられているらしい。 グローバル変数などは外部リンケージ。このほうが局所的には楽ちんだが大きなプロダクトを作っているときはシンボル重複を避けたりauthorが想定しない使われ方をさせないために、ファイル外からの参照を禁止したいときがある。これが内部リンケージ。 ```cpp= static bool kStatic = true; ``` こうかけばいい。 ところで、anonymous namespaceで宣言されたシンボルは内部リンケージを持つ。それらのシンボルは外部には見えず参照できない。 static装飾子と実質同じっぽい。 ## Anonymous Namaspace vs static [Cpp core guidline](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#sf22-use-an-unnamed-anonymous-namespace-for-all-internalnon-exported-entities)によるとstaticよりanonymous namespaceを使えとある。 ぱっと思いつくメリットでは、namespace後のインデントがないGoogle coding styleにおいてはstaticよりnamespaceの方がインデントが浅く読みやすい。 また、`{}`括りで中に変数や関数を書くので、必然的にlocalな関数・変数がまとまってくれて読みやすい。 ## ヘッダファイルやPrivate methods との比較 他のファイルから参照する必要のない関数について、どういう書き方が他にあり、どれが良いかについても考えてみよう。 他の選択肢としてヘッダファイルの中で宣言したり、クラスを作っている場合はクラスのprivate関数として実装することもできる。これらとの比較についても[abseil tips](https://abseil.io/tips/186)を参考に確認する。 - そもそもヘッダファイルよりccにある方が同じファイル内で見つけやすく、コメント・宣言・実装が同じところにあると見やすい。 - (elkurin) この文章自体は賛成しかねる。Chromiumくらいデカイプロダクトになると、とりあえずヘッダファイルを見て関数のリストを見たい要求が大きいと思う。しかし、anonymous namespaceにつっこめるケースというのはその関数はそのファイルからしか使われないようなケースなので、そういう関数がヘッダファイルを汚していると見にくいため、結論ccにいてくれたほうがありがたい。 - 他のファイルから隔離することでrefactorしやすい (private関数はのぞく) - input / output がより明確。クラスのメンバ変数を参照したり上書きしたりできないので、関数の引数や返り値で副作用なく処理できる。 - private関数の場合いい感じにconstをつけることで上書きを縛ったりもできるが、そういうのに気を配らなくていいというのはメリットだと思う。 ヘッダファイルで宣言したほうが良さそうなケースがないわけではない。例えば - クラスの他のメンバ変数や関数とややこしいinteractionがある場合。例えばいろんなメンバ引数にアクセスしたいときにそれを全部渡すのは効率が悪いし読みにくい。複数の状態を上書きしたい場合も、ぐちゃぐちゃの返り値で頑張るよりprivateメンバ変数と直接しゃべるほうが読みやすい。 - (elkurin) 非同期に走らせたい関数。同期的なものは引数で必要な値を渡せばよいが、非同期的に走るが走るときのメンバ変数の値を参照したい場合はクラスと紐付けて走らせる必要がある。Chromium的に言えば、クラスオブジェクトのWeakPtrと一緒にBindOnceしてどっかのThreadにPostTask。 ```cpp= // 特にメンバ変数などとinteractionがないケースはanonymousに namespace { void RecordDataVerForPrimaryUser() { const std::string user_id_hash = ash::BrowserContextHelper::GetUserIdHashFromBrowserContext( ProfileManager::GetPrimaryUserProfile()); crosapi::browser_util::RecordDataVer(g_browser_process->local_state(), user_id_hash, version_info::GetVersion()); } } // namespace WaitForProfileAddedAndThen(base::BindOnce(&RecordDataVerForPrimaryUser)); // メンバ変数や関数といっぱい関わる場合はprivate member関数に void BrowserManager::OnLoadComplete(bool launching_at_login_screen, const base::FilePath& path, LacrosSelection selection, base::Version version) { if (shutdown_requested_) { LOG(ERROR) << "Load completed after Shutdown() called."; return; } DCHECK_EQ(state_, State::MOUNTING); lacros_path_ = path; lacros_selection_ = absl::optional<LacrosSelection>(selection); const bool success = !path.empty(); SetState(success ? State::STOPPED : State::UNAVAILABLE); for (auto& observer : observers_) { observer.OnLoadComplete(success, version); } StartIfNeeded(launching_at_login_screen); } browser_loader_->Load(base::BindOnce( &BrowserManager::OnLoadComplete, weak_factory_.GetWeakPtr(), false)); ``` ## Summary 他のファイルから参照されない関数はanonymous namespaceに入れるかprivateメンバにしよう。 引数が多すぎたり、クラスオブジェクトと密につながっているときはprivateメンバにするのもいい。 ## Note ところでC++規格上の正式名称は unnamed namespace らしい。