592

C ++の機能は、次のように、名前のない(匿名の)名前空間を作成する機能です。

namespace {
    int cannotAccessOutsideThisFile() { ... }
} // namespace

このような機能は役に立たないと思うでしょう。名前空間の名前を指定できないため、外部からその中の何かにアクセスすることは不可能です。ただし、これらの名前のない名前空間には、暗黙のusing句があるかのように、それらが作成されたファイル内でアクセスできます。

私の質問は、静的関数を使用するよりも、なぜ、またはいつこれが望ましいのかということです。それとも、まったく同じことを行う2つの方法ですか?

4

11 に答える 11

384

C ++標準は、セクション7.3.1.1名前空間の段落2を読み取ります。

名前空間スコープでオブジェクトを宣言する場合、staticキーワードの使用は非推奨になります。名前空間なしは、優れた代替手段を提供します。

静的は、オブジェクト、関数、および匿名ユニオンの名前にのみ適用され、型宣言には適用されません。

編集:

このstaticキーワードの使用を廃止するという決定(翻訳単位での変数宣言の可視性に影響を与える)は逆になりました(ref)。この場合、staticまたは名前のないものを使用するnamespaceと、まったく同じことを行う2つの方法に戻ります。詳細については、このSOの質問を参照してください。

名前namespaceのないものには、translation-unit-local型を定義できるという利点があります。詳細については、このSOの質問を参照してください。

これを私の注意を引いたのはマイク・パーシーの功績です。

于 2008-09-30T19:06:19.613 に答える
84

メソッドを無名の名前空間に置くことで、One Definition Ruleに誤って違反することを防ぎ、ヘルパー メソッドにリンクする可能性のある他のメソッドと同じ名前を付けることを心配する必要がなくなります。

そして、によって指摘されたようにluke、匿名の名前空間は、静的メンバーよりも標準で優先されます。

于 2008-09-30T23:20:49.690 に答える
41

静的が驚くべき効果をもたらすエッジケースが1つあります(少なくとも私にはそうでした)。C++03 標準では、14.6.4.2/1 で次のように述べられています。

テンプレート パラメーターに依存する関数呼び出しの場合、関数名がunqualified-idであるがtemplate-idではない場合、候補関数は通常の検索規則 (3.4.1、3.4.2) を使用して検索されますが、次の点が異なります。

  • 非修飾名ルックアップ (3.4.1) を使用したルックアップの部分では、テンプレート定義コンテキストからの外部リンケージを持つ関数宣言のみが検出されます。
  • 関連付けられた名前空間 (3.4.2) を使用したルックアップの部分では、テンプレート定義コンテキストまたはテンプレート インスタンス化コンテキストで見つかった外部リンケージを持つ関数宣言のみが見つかります。

...

以下のコードは呼び出しますが、期待どおりではfoo(void*)ありませfoo(S const &)ん。

template <typename T>
int b1 (T const & t)
{
  foo(t);
}

namespace NS
{
  namespace
  {
    struct S
    {
    public:
      operator void * () const;
    };

    void foo (void*);
    static void foo (S const &);   // Not considered 14.6.4.2(b1)
  }

}

void b2()
{
  NS::S s;
  b1 (s);
}

これ自体はおそらくそれほど大きな問題ではありませんが、完全に準拠した C++ コンパイラ (つまり、 をサポートするものexport) の場合、staticキーワードは他の方法では利用できない機能を引き続き備えていることを強調しています。

// bar.h
export template <typename T>
int b1 (T const & t);

// bar.cc
#include "bar.h"
template <typename T>
int b1 (T const & t)
{
  foo(t);
}

// foo.cc
#include "bar.h"
namespace NS
{
  namespace
  {
    struct S
    {
    };

    void foo (S const & s);  // Will be found by different TU 'bar.cc'
  }
}

void b2()
{
  NS::S s;
  b1 (s);
}

名前のない名前空間の関数が、ADL を使用するテンプレートで見つからないようにする唯一の方法は、それを作成することstaticです。

最新の C++ の更新

C++ '11 の時点で、名前のない名前空間のメンバーには暗黙的に内部リンケージがあります (3.5/4):

名前のない名前空間、または名前のない名前空間内で直接的または間接的に宣言された名前空間には、内部リンケージがあります。

しかし同時に、14.6.4.2/1 が更新され、リンケージの言及が削除されました (これは C++ '14 から取得されたものです)。

postfix-expression が従属名である関数呼び出しの場合、次の点を除いて、通常のルックアップ規則 (3.4.1、3.4.2) を使用して候補関数が検索されます。

  • 非修飾名ルックアップ (3.4.1) を使用したルックアップの部分では、テンプレート定義コンテキストからの関数宣言のみが見つかります。

  • 関連付けられた名前空間 (3.4.2) を使用したルックアップの部分では、テンプレート定義コンテキストまたはテンプレート インスタンス化コンテキストのいずれかで見つかった関数宣言のみが見つかります。

その結果、静的な名前空間メンバーと名前のない名前空間メンバーの間のこの特定の違いはなくなりました。

于 2008-10-01T09:15:19.370 に答える
12

私は最近、静的キーワードをコード内の匿名名前空間に置き換え始めましたが、すぐに名前空間内の変数がデバッガーで検査できなくなるという問題に遭遇しました。私は VC60 を使用していたので、それが他のデバッガーで問題ないかどうかはわかりません。私の回避策は、「モジュール」名前空間を定義することでした。ここで、cpp ファイルの名前を付けました。

たとえば、私の XmlUtil.cpp ファイルでは、XmlUtil_I { ... }すべてのモジュール変数と関数の名前空間を定義しています。XmlUtil_I::そうすれば、デバッガーで修飾を適用して変数にアクセスできます。この場合、他の場所で使用したい_Iパブリック名前空間とは区別されます。XmlUtil

真に匿名のアプローチと比較したこのアプローチの潜在的な欠点は、誰かが他のモジュールで名前空間修飾子を使用して、目的の静的スコープに違反する可能性があることだと思います。それが大きな懸念事項かどうかはわかりませんが。

于 2008-10-01T00:39:12.090 に答える
8

経験上、以前は静的だった関数を無名名前空間に配置するのは C++ の方法ですが、古いコンパイラではこれに問題がある場合があることに注意してください。私は現在、ターゲット プラットフォーム用にいくつかのコンパイラを使用していますが、最新の Linux コンパイラは、匿名名前空間に関数を配置しても問題ありません。

しかし、特定されていない将来のリリースまで私たちが慣れ親しんでいるSolarisで実行されている古いコンパイラは、それを受け入れる場合もあれば、エラーとしてフラグを立てる場合もあります. エラーは私が心配していることではなく、それを受け入れるときに何をしているのということです。したがって、全面的に最新化するまでは、匿名名前空間を優先する静的 (通常はクラス スコープ) 関数を引き続き使用します。

于 2008-10-26T20:43:26.557 に答える
7

その目的で static キーワードを使用することは、C++98 標準では推奨されていません。static の問題は、それが型定義に適用されないことです。これは、さまざまなコンテキストでさまざまな方法で使用されるオーバーロードされたキーワードでもあるため、名前のない名前空間は物事を少し単純化します。

于 2008-09-30T19:13:35.273 に答える
3

さらに、次の例のように、変数で static キーワードを使用する場合:

namespace {
   static int flag;
}

マッピング ファイルには表示されません。

于 2011-12-08T19:02:23.557 に答える
-1

あなたの質問を読んでいるときにこの機能を知ったのは今だけなので、推測することしかできません。これは、ファイルレベルの静的変数よりもいくつかの利点があるようです:

  • 匿名の名前空間は互いに入れ子にすることができ、シンボルがエスケープできない複数レベルの保護を提供します。
  • 複数の匿名名前空間を同じソース ファイルに配置して、同じファイル内に異なる静的レベルのスコープを作成することができます。

実際のコードで匿名の名前空間を使用したことがある人がいるかどうかを知りたいです。

于 2008-09-30T19:09:26.597 に答える