名前空間 (C++)Namespaces (C++)

名前空間は、その内部にある識別子 (型、関数、変数などの名前) のスコープを定める宣言領域です。A namespace is a declarative region that provides a scope to the identifiers (the names of types, functions, variables, etc) inside it. 名前空間は、コードを論理グループにまとめるため、およびコード ベースに複数のライブラリが含まれる場合に特に発生する名前の競合を回避するために使用されます。Namespaces are used to organize code into logical groups and to prevent name collisions that can occur especially when your code base includes multiple libraries. 名前空間スコープのすべての識別子は互いどうしを修飾なしで参照できます。All identifiers at namespace scope are visible to one another without qualification. 名前空間の外側の識別子は、各識別子std::vector<std::string> vec;の完全修飾名を使用するか、単一の識別子 (using std::string) の using宣言によって、またはすべてに対して using ディレクティブを使用して、メンバーにアクセスできます。名前空間の識別子 (using namespace std;)。Identifiers outside the namespace can access the members by using the fully qualified name for each identifier, for example std::vector<std::string> vec;, or else by a using Declaration for a single identifier (using std::string), or a using Directive for all the identifiers in the namespace (using namespace std;). ヘッダー ファイル内のコードは、常に完全修飾された名前空間の名前を使用する必要があります。Code in header files should always use the fully qualified namespace name.

次の例は、名前空間宣言とともに、名前空間の外部のコードがメンバーにアクセスできる 3 つの方法を示しています。The following example shows a namespace declaration and three ways that code outside the namespace can accesses their members.

namespace ContosoData
{
    class ObjectManager
    {
    public:
        void DoSomething() {}
    };
    void Func(ObjectManager) {}
}

完全修飾名の使用:Use the fully qualified name:

ContosoData::ObjectManager mgr;
mgr.DoSomething();
ContosoData::Func(mgr);

using 宣言を使用すると、1 つの識別子をスコープに挿入できます。Use a using declaration to bring one identifier into scope:

using ContosoData::ObjectManager;
ObjectManager mgr;
mgr.DoSomething();

using ディレクティブを使用すると、名前空間にあるすべてのものをスコープに挿入できます。Use a using directive to bring everything in the namespace into scope:

using namespace ContosoData;

ObjectManager mgr;
mgr.DoSomething();
Func(mgr);

ディレクティブの使用using directives

Usingディレクティブを使用すると、名前空間内のすべての名前を明示的な修飾子として使用することができます。The using directive allows all the names in a namespace to be used without the namespace-name as an explicit qualifier. 名前空間で複数の異なる識別子を使用している場合は、実装ファイル (* .cpp) で using ディレクティブを使用します。識別子を1つまたは2つだけ使用している場合は、名前空間内のすべての識別子ではなく、その識別子だけをスコープに取り込むための宣言を使用することを検討してください。Use a using directive in an implementation file (i.e. *.cpp) if you are using several different identifiers in a namespace; if you are just using one or two identifiers, then consider a using declaration to only bring those identifiers into scope and not all the identifiers in the namespace. ローカル変数に名前空間変数と同じ名前が付いている場合、名前空間変数が不可視になります。If a local variable has the same name as a namespace variable, the namespace variable is hidden. グローバル変数と同じ名前の名前空間変数を使用するとエラーになります。It is an error to have a namespace variable with the same name as a global variable.

注意

using ディレクティブは、.cpp ファイルの冒頭に配置するか (ファイル スコープ)、クラス内または関数定義内に配置できます。A using directive can be placed at the top of a .cpp file (at file scope), or inside a class or function definition.

通常は、using ディレクティブをヘッダー ファイル (*.h) に配置することは避けてください。このヘッダーをインクルードするすべてのファイルが、名前空間にあるすべてのものをスコープに挿入して、デバッグが非常に困難な名前の隠蔽の問題や名前の競合の問題を引き起こすことがあるためです。In general, avoid putting using directives in header files (*.h) because any file that includes that header will bring everything in the namespace into scope, which can cause name hiding and name collision problems that are very difficult to debug. ヘッダー ファイルには常に完全修飾名を使用してください。Always use fully qualified names in a header file. 完全修飾名が長すぎる場合は、名前空間のエイリアスを使用して短縮します。If those names get too long, you can use a namespace alias to shorten them. (以下を参照してください。)(See below.)

名前空間と名前空間のメンバーの宣言Declaring namespaces and namespace members

一般的に、名前空間はヘッダー ファイル内で宣言します。Typically, you declare a namespace in a header file. 関数の実装が別のファイルにある場合は、次の例のように関数名を修飾します。If your function implementations are in a separate file, then qualify the function names, as in this example.

//contosoData.h
#pragma once
namespace ContosoDataServer
{
    void Foo();
    int Bar();
}

ファイルの先頭にusingディレクティブを配置した場合でも、contosodata の関数実装では完全修飾名を使用する必要があります。Function implementations in contosodata.cpp should use the fully qualified name, even if you place a using directive at the top of the file:

#include "contosodata.h"
using namespace ContosoDataServer;

void ContosoDataServer::Foo() // use fully-qualified name here
{
   // no qualification needed for Bar()
   Bar();
}

int ContosoDataServer::Bar(){return 0;}

名前空間は、1 つのファイルにある複数のブロック、および複数のファイルで宣言できます。A namespace can be declared in multiple blocks in a single file, and in multiple files. コンパイラは、プリプロセス時にパーツを結合します。結果として生成される名前空間には、すべてのパーツで宣言されるすべてのメンバーが含まれます。The compiler joins the parts together during preprocessing and the resulting namespace contains all the members declared in all the parts. この一例が、標準ライブラリの各ヘッダー ファイルで宣言されている std 名前空間です。An example of this is the std namespace which is declared in each of the header files in the standard library.

名前付き名前空間のメンバーは、定義されている名前を明示的に修飾することによって宣言されている名前空間の外部で定義できます。Members of a named namespace can be defined outside the namespace in which they are declared by explicit qualification of the name being defined. ただし、定義は、宣言の名前空間を囲う名前空間内で、宣言の位置の後に記述する必要があります。However, the definition must appear after the point of declaration in a namespace that encloses the declaration's namespace. 例えば:For example:

// defining_namespace_members.cpp
// C2039 expected
namespace V {
    void f();
}

void V::f() { }        // ok
void V::g() { }        // C2039, g() is not yet a member of V

namespace V {
    void g();
}

このエラーは、名前空間のメンバーが複数のヘッダー ファイルで宣言されており、かつこれらのヘッダーを正しい順序でインクルードしなかった場合に発生します。This error can occur when namespace members are declared across multiple header files, and you have not included those headers in the correct order.

グローバル名前空間The global namespace

識別子は、明示的な名前空間で宣言されていない場合は、暗黙のグローバル名前空間の一部になります。If an identifier is not declared in an explicit namespace, it is part of the implicit global namespace. 一般に、可能であればグローバルスコープで宣言を作成しないようにしてください。ただし、グローバル名前空間に存在する必要があるエントリポイントのMain 関数は除きます。In general, try to avoid making declarations at global scope when possible, except for the entry point main Function, which is required to be in the global namespace. グローバル識別子を明示的に修飾するには、::SomeFunction(x); のように、名前のないスコープ解決演算子を使用します。To explicitly qualify a global identifier, use the scope resolution operator with no name, as in ::SomeFunction(x);. これにより、識別子は他のあらゆる名前空間にある同じ名前のすべてのものから区別され、コードも他のユーザーに理解しやすいものになります。This will differentiate the identifier from anything with the same name in any other namespace, and it will also help to make your code easier for others to understand.

std 名前空間The std namespace

すべてC++の標準ライブラリの型と関数は、 stdstdで入れ子になっている名前空間または名前空間で宣言されます。All C++ standard library types and functions are declared in the std namespace or namespaces nested inside std.

入れ子になった名前空間Nested namespaces

名前空間は入れ子にすることができます。Namespaces may be nested. 次の例に示すように、入れ子になった通常の名前空間には、その親メンバーへの非修飾のアクセス権がありますが、親メンバーには (インラインとして宣言されていない限り) 入れ子になった名前空間への非修飾のアクセス権がありません。An ordinary nested namespace has unqualified access to its parent’s members, but the parent members do not have unqualified access to the nested namespace (unless it is declared as inline), as shown in the following example:

namespace ContosoDataServer
{
    void Foo();

    namespace Details
    {
        int CountImpl;
        void Ban() { return Foo(); }
    }

    int Bar(){...};
    int Baz(int i) { return Details::CountImpl; }
}

入れ子になった通常の名前空間は、親の名前空間のパブリック インターフェイスの一部ではない内部実装の詳細をカプセル化するために使用できます。Ordinary nested namespaces can be used to encapsulate internal implementation details that are not part of the public interface of the parent namespace.

インライン名前空間 (C++ 11)Inline namespaces (C++ 11)

入れ子になった通常の名前空間とは対照的に、インライン名前空間のメンバーは親の名前空間のメンバーとして扱われます。In contrast to an ordinary nested namespace, members of an inline namespace are treated as members of the parent namespace. この特性のおかげで、オーバーロードされた関数に対する引数依存の参照を、親の名前空間と入れ子のインライン名前空間にオーバーロードを持つ関数に対して使用できます。This characteristic enables argument dependent lookup on overloaded functions to work on functions that have overloads in a parent and a nested inline namespace. また、インライン名前空間で宣言されているテンプレートの特殊化を親の名前空間で宣言することもできます。It also enables you to declare a specialization in a parent namespace for a template that is declared in the inline namespace. 次の例は、外部のコードを既定でインライン名前空間にバインドする方法を示しています。The following example shows how external code binds to the inline namespace by default:

//Header.h
#include <string>

namespace Test
{
    namespace old_ns
    {
        std::string Func() { return std::string("Hello from old"); }
    }

    inline namespace new_ns
    {
        std::string Func() { return std::string("Hello from new"); }
    }
}

#include "header.h"
#include <string>
#include <iostream>

int main()
{
    using namespace Test;
    using namespace std;

    string s = Func();
    std::cout << s << std::endl; // "Hello from new"
    return 0;
}

次の例は、インライン名前空間で宣言されているテンプレートの特殊化を親で宣言する方法を示しています。The following example shows how you can declare a specialization in a parent of a template that is declared in an inline namespace:

namespace Parent
{
    inline namespace new_ns
    {
         template <typename T>
         struct C
         {
             T member;
         };
    }
     template<>
     class C<int> {};
}

ライブラリのパブリック インターフェイスに対する変更を管理するためのバージョン管理のメカニズムとして、インライン名前空間を使用することができます。You can use inline namespaces as a versioning mechanism to manage changes to the public interface of a library. たとえば、単一の親名前空間を作成し、インターフェイスの各バージョンを、親の中に入れ子になっている、それぞれ独自の名前空間にカプセル化することができます。For example, you can create a single parent namespace, and encapsulate each version of the interface in its own namespace nested inside the parent. 最新または最優先のバージョンを保持する名前空間をインラインとして修飾することで、これを親の名前空間の直接のメンバーであるかのように公開できます。The namespace that holds the most recent or preferred version is qualified as inline, and is therefore exposed as if it were a direct member of the parent namespace. Parent::Class を呼び出すクライアント コードは、新しいコードに自動的にバインドされます。Client code that invokes the Parent::Class will automatically bind to the new code. 古いバージョンを使用するクライアントは、そのコードを持つ入れ子になった名前空間への完全修飾パスを使用すれば、引き続き古いバージョンにアクセスできます。Clients that prefer to use the older version can still access it by using the fully qualified path to the nested namespace that has that code.

inline キーワードは、コンパイル単位内の名前空間の最初の宣言に適用する必要があります。The inline keyword must be applied to the first declaration of the namespace in a compilation unit.

次の例は、あるインターフェイスの 2 つのバージョンを示しています。それぞれ入れ子になった名前空間に置かれています。The following example shows two versions of an interface, each in a nested namespace. v_20 名前空間には、v_10 インターフェイスからの変更があり、インラインとしてマークされます。The v_20 namespace has some modification from the v_10 interface and is marked as inline. 新しいライブラリを使用し、Contoso::Funcs::Add を呼び出すクライアント コードは、v_20 バージョンを呼び出します。Client code that uses the new library and calls Contoso::Funcs::Add will invoke the v_20 version. Contoso::Funcs::Divide を呼び出そうとするコードは、コンパイル時エラーになります。Code that attempts to call Contoso::Funcs::Divide will now get a compile time error. その関数が実際に必要な場合は、明示的に Contoso::v_10::Funcs::Divide を呼び出して引き続き v_10 バージョンにアクセスすることができます。If they really need that function, they can still access the v_10 version by explicitly calling Contoso::v_10::Funcs::Divide.

namespace Contoso
{
    namespace v_10
    {
        template <typename T>
        class Funcs
        {
        public:
            Funcs(void);
            T Add(T a, T b);
            T Subtract(T a, T b);
            T Multiply(T a, T b);
            T Divide(T a, T b);
        };
    }

    inline namespace v_20
    {
        template <typename T>
        class Funcs
        {
        public:
            Funcs(void);
            T Add(T a, T b);
            T Subtract(T a, T b);
            T Multiply(T a, T b);
            std::vector<double> Log(double);
            T Accumulate(std::vector<T> nums);
      };
    }
}

名前空間のエイリアスNamespace aliases

名前空間の名前は一意である必要があります。つまり、多くの場合、短くなりすぎないようにする必要があります。Namespace names need to be unique, which means that often they should not be too short. 名前が長くてコードが読みにくい場合、または using ディレクティブを使用できないヘッダー ファイルに入力するのが面倒な場合は、実際の名前の省略形として機能する名前空間のエイリアスを作成することができます。If the length of a name makes code difficult to read, or is tedious to type in a header file where using directives can’t be used, then you can make a namespace alias which serves as an abbreviation for the actual name. 例えば:For example:

namespace a_very_long_namespace_name { class Foo {}; }
namespace AVLNN = a_very_long_namespace_name;
void Bar(AVLNN::Foo foo){ }

匿名または名前のない名前空間anonymous or unnamed namespaces

名前を付けないで明示的な名前空間を作成することができます。You can create an explicit namespace but not give it a name:

namespace
{
    int MyFunc(){}
}

これは名前のない名前空間または匿名の名前空間と呼ばれ、名前付きの名前空間を作成しなくても、変数の宣言を他のファイルのコードに対して非表示にする場合に便利です。This is called an unnamed or anonymous namespace and it is useful when you want to make variable declarations invisible to code in other files (i.e. give them internal linkage) without having to create a named namespace. 同じファイル内のすべてのコードは名前のない名前空間の識別子を参照できますが、そのファイルの外 (より厳密に言えば、翻訳単位の外) では、識別子および名前空間自体が不可視になります。All code in the same file can see the identifiers in an unnamed namespace but the identifiers, along with the namespace itself, are not visible outside that file—or more precisely outside the translation unit.

関連項目See also

宣言と定義Declarations and Definitions