21

私が変更するように求められたいくつかのコードは、次のようになります。

namespace XXX {

namespace {

// some stuff

} // end of unnamed

// Some stuff within the scope of XXX

} // end of XXX

名前のない名前空間を別の名前空間に埋め込むことの利点を見つけるのに苦労しており、次のように変更することを検討しています。

namespace {

// some stuff

} // end of unnamed

namespace XXX {

// Some stuff within the scope of XXX

} // end of XXX

どんな意見でもありがたいです。

4

5 に答える 5

21

実用的な利点があります。名前のない名前空間は、その内部の名前をさまざまな翻訳単位から隠します。

上記のコードは、foo の定義が同じ翻訳単位にあるためにのみ機能します。

main() と foo() の定義が異なる翻訳単位にあるとします。メインファイルには宣言のヘッダーが含まれているため、コンパイルされます。しかし、論理的には X::(無名の名前空間)::foo のようなものは存在しないため、リンクしません。

于 2013-01-07T18:23:40.547 に答える
7

さて、それX::<anonymous>::foo()はとして表示さX::foo()れていることがわかりました。びっくりしました。

したがって、実際的なメリットはほとんどありません。ただし、セマンティックまたはドキュメントに影響がある場合があります。


元の回答

そうですね、それはむしろ「もの」に依存しますね。

既存のコードを使用すると、コードインに、同じように含まれているが外部からアクセスできないX他のものを「プライベート」に含めることができます。XX

#include <iostream>

namespace X {
   namespace {
      void foo() { std::cout << "lol\n"; }
   }
   
   void bar() { foo(); }
}

int main()
{
   X::bar();
   // X::foo();  // can't do this directly  [edit: turns out we can!]
}
  • 出力:lol\n

提案されたアプローチにより、その「プライベートなもの」を翻訳ユニット全体で利用できるようになります。

#include <iostream>

namespace {
   void foo() { std::cout << "lol\n"; }
}

namespace X {
   void bar() { foo(); }
}

int main()
{
   X::bar();
   foo();     // works
}
  • 出力:lol\nlol\n
于 2013-01-07T17:32:52.263 に答える
7

グローバルな観点からのメリットはほとんどありません。他の翻訳単位の観点から見ると、どちらのアプローチも同じ結果になります。匿名の名前空間は見えません (または参照できません)。

同じ翻訳単位の観点から、違いがあります。トップレベルの名前空間を定義しているという事実は、他の場所で宣言された名前空間の競合をインポートする可能性を減らすことを意味し、最も一般的なものはグローバル名前空間 (名前空間なし) に対するものです。 stdio.h などの ISO C から継承されたものを考えてください)。

たとえば、その翻訳単位でインポートするグローバル ヘッダーに「名前空間のない」abort() があり、翻訳単位で名前空間 { abort() { ...} } を宣言すると、あいまいさ、たとえば gcc が発生します。コンパイルエラーをスローします:

error: call of overloaded ‘abort()’ is ambiguous

ここで、名前付き名前空間内で匿名名前空間に名前を付けると、次の効果があります。

a) 優先順位があるため、名前空間内で宣言された関数にあいまいさはありません。

namespace a { namespace { abort() {...} } }

a::whatever() のような関数があり、abort() を参照する場合、それが優先されるため、独自の名前空間で解決されます。

b) 名前空間 { abort(); と同じように、翻訳単位の外に存在しないため、 a::abort() のグローバルリンケージはありません。} はトップレベルにありますが、上記の潜在的な競合はありません。

そして、「b」に違いがあります。これは単なる名前空間 a { abort(); と同じではありません。グローバルリンケージがないため、競合することなく別の翻訳単位で再定義できます。名前空間 a { abort() { ... } } ... を定義する 2 つの翻訳単位をリンクしようとして頑張ってください。

したがって、あなたが意味するとおりになります:

namespace a { // you have a named space, so you don't have conflicts with the nameless one
  namespace { // but you have local visibility and linkage
    whatever(); // for this
  }
}

要するに、どちらの方法にも類似点がありますが、違いがあります。それはあまり役に立たないと主張する人もいるかもしれませんが、スタイルとして、グローバル名前空間との衝突を予防的に回避します。これらはコンパイル時に (願わくば、少なくとも署名が完全に一致する場合に) キャッチされるため、なぜ気にする必要があるのか​​ 、という議論ができます。ただし、プロジェクトが移植可能なライブラリであり、環境ヘッダー自体がインポートするものに応じてヘッダーが汚染される可能性がある場合、これは便利な概念です。そうしないと、ユーザーはシステム用にライブラリにパッチを適用するか、#ifdefs が必要になります。あちこち。

私は ISO/ANSI C 99 で多くのプログラミングを行っており、時々次のようなことをしなければなりません:

#include <headerA.h>
#define symbol symbolB
#include <headerB.h>
// or some crap alike. And I have linker problems with above.

...両方のヘッダー(たとえば、異なるライブラリから)が名前空間を汚染し、他の誰かのライブラリに単純にパッチを当てることができないためです。

C++ 名前空間は、他の誰かがそれを使用しない場合を除いて、それを解決するため、防止する (レガシー コードのオプションではない) またはそれを打ち消すための措置を講じる必要があります

于 2015-03-31T12:37:22.267 に答える