名前空間
変種
操作

非修飾名のルックアップ

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

修飾されていない名前、つまりスコープ解決演算子::の右辺に現れない名前の場合、名前検索は以下に説明するスコープを調べ、少なくとも1つの宣言が見つかるまで続行します。その時点で検索は停止し、それ以上のスコープは調べられません。(注: 一部のコンテキストからの検索では、一部の宣言がスキップされます。たとえば、::の左辺で使用される名前の検索では、関数、変数、列挙子の宣言は無視されます。基底クラス指定子として使用される名前の検索では、型以外のすべての宣言は無視されます。)

修飾されていない名前検索の目的上、using directiveによって指定された名前空間からのすべての宣言は、using-directiveと指定された名前空間の両方を直接的または間接的に含む、最も近い囲む名前空間に宣言されたかのように現れます。

関数呼び出し演算子(および同等に、式中の演算子)の左辺で使用される名前の修飾されていない名前検索は、引数依存検索で説明されています。

目次

[編集] ファイルスコープ

グローバル(トップレベル名前空間)スコープで、関数、クラス、またはユーザー定義名前空間の外で使用される名前の場合、名前の使用前のグローバルスコープが調べられます。

int n = 1;     // declaration of n
int x = n + 1; // OK: lookup finds ::n
 
int z = y - 1; // Error: lookup fails
int y = 2;     // declaration of y

[編集] 名前空間スコープ

ユーザー定義名前空間内で、関数またはクラスの外で使用される名前の場合、名前の使用前のこの名前空間が検索され、次にこの名前空間を囲む、この名前空間の宣言前の名前空間が検索され、グローバル名前空間に到達するまで続きます。

int n = 1; // declaration
 
namespace N
{
    int m = 2;
 
    namespace Y
    {
        int x = n; // OK, lookup finds ::n
        int y = m; // OK, lookup finds ::N::m
        int z = k; // Error: lookup fails
    }
 
    int k = 3;
}

[編集] 名前空間外での定義

名前空間外での名前空間メンバ変数の定義で使用される名前の場合、検索は、名前空間内での使用の場合と同じように進行します。

namespace X
{
    extern int x; // declaration, not definition
    int n = 1;    // found 1st
}
 
int n = 2;        // found 2nd
int X::x = n;     // finds X::n, sets X::x to 1

[編集] 非メンバ関数の定義

関数定義(本体内またはデフォルト引数の一部)で使用される名前で、その関数がユーザー定義名前空間またはグローバル名前空間のメンバである場合、名前の使用前のブロックが検索され、次にそのブロックの開始前の囲むブロックが検索され、関数本体であるブロックに到達するまで続きます。次に、関数が宣言された名前空間が、名前を使用する関数の定義(必ずしも宣言ではない)まで検索され、次に囲む名前空間が検索されます。

namespace A
{
    namespace N
    {
        void f();
        int i = 3; // found 3rd (if 2nd is not present)
    }
 
    int i = 4;     // found 4th (if 3rd is not present)
}
 
int i = 5;         // found 5th (if 4th is not present)
 
void A::N::f()
{
    int i = 2;     // found 2nd (if 1st is not present)
 
    while (true)
    {
       int i = 1;  // found 1st: lookup is done
       std::cout << i;
    }
}
 
// int i;          // not found
 
namespace A
{
    namespace N
    {
        // int i;  // not found
    }
}

[編集] クラス定義

クラス定義(基底クラス指定子やネストクラス定義を含む)のどこかで(メンバ関数本体、メンバ関数のデフォルト引数、メンバ関数の例外指定子、またはデフォルトメンバ初期化子を除く)使用される名前の場合、メンバは囲むクラスの本体で定義されているネストクラスのものである可能性があり、以下のスコープが検索されます。

a) 名前が使用されているクラスの本体(使用箇所まで)。
b) 基底クラスの本体全体(宣言が見つからない場合、その基底クラスの基底クラスも再帰的に検索)。
c) そのクラスがネストされている場合、囲むクラスの本体(このクラスの定義まで)とその囲むクラスの基底クラスの本体全体。
d) そのクラスがローカルクラスである場合、またはローカルクラス内にネストされている場合、クラスが定義されているブロックのスコープ(定義箇所まで)。
e) そのクラスが名前空間のメンバである場合、または名前空間のメンバであるクラスにネストされている場合、または名前空間のメンバである関数内のローカルクラスである場合、その名前空間のスコープはクラス、囲むクラス、または関数の定義まで検索されます。検索は、それらを囲む名前空間までグローバルスコープに到達するまで続行します。

フレンド宣言の場合、以前に宣言されたエンティティを参照しているかを判断するための検索は上記のように進行しますが、最も内側の囲む名前空間に到達した時点で停止します。

namespace M
{
    // const int i = 1; // never found
 
    class B
    {
        // static const int i = 3;     // found 3rd (but will not pass access check)
    };
}
 
// const int i = 5;                    // found 5th
 
namespace N
{
    // const int i = 4;                // found 4th
 
    class Y : public M::B
    {
        // static const int i = 2;     // found 2nd
 
        class X
        {
            // static const int i = 1; // found 1st
            int a[i]; // use of i
            // static const int i = 1; // never found
        };
 
        // static const int i = 2;     // never found
    };
 
    // const int i = 4;                // never found
}
 
// const int i = 5;                    // never found

[編集] 注入されたクラス名

そのクラスまたはテンプレートの定義内、またはそれから派生したクラスまたはテンプレート内で使用されるクラスまたはクラステンプレートの名前の場合、修飾されていない名前検索では、あたかもその名前がメンバ宣言によって導入されたかのように(パブリックメンバアクセスで)、定義されているクラスが見つかります。詳細については、注入されたクラス名を参照してください。

[編集] メンバ関数の定義

メンバ関数本体、メンバ関数のデフォルト引数、メンバ関数の例外指定子、またはデフォルトメンバ初期化子内で使用される名前の場合、検索されるスコープはクラス定義と同じですが、クラスのスコープ全体が考慮され、名前を使用する宣言より前の部分だけではありません。ネストクラスの場合、囲むクラスの本体全体が検索されます。

class B
{
    // int i;         // found 3rd
};
 
namespace M
{
    // int i;         // found 5th
 
    namespace N
    {
        // int i;     // found 4th
 
        class X : public B
        {
            // int i; // found 2nd
            void f();
            // int i; // found 2nd as well
        };
 
        // int i;     // found 4th
    }
}
 
// int i;             // found 6th
 
void M::N::X::f()
{
    // int i;         // found 1st
    i = 16;
    // int i;         // never found
}
 
namespace M
{
    namespace N
    {
        // int i;     // never found
    }
}
いずれの場合も、クラスが派生する基底クラスを調べるとき、以下の規則(仮想継承における支配と呼ばれることもある)が従われます。
サブオブジェクトBで見つかったメンバ名は、ABの基底クラスサブオブジェクトである場合、任意のサブオブジェクトAの同じメンバ名を隠します。(これは、継承格子上のAの追加の非仮想コピーの名前を隠すわけではないことに注意してください。この規則は、仮想継承にのみ影響します。)using宣言によって導入された名前は、宣言を含むクラスの名前として扱われます。各基底を調べた後、結果のセットには、同じ型の静的メンバの宣言、または同じサブオブジェクトからの非静的メンバの宣言が含まれている必要があります。 (C++11まで)
「検索セット」が構築され、これには宣言とその宣言が見つかったサブオブジェクトが含まれます。using宣言は、それが表すメンバに置き換えられ、型宣言(注入されたクラス名を含む)は、それが表す型に置き換えられます。Cが名前が使用されたクラスである場合、まずCが調べられます。Cの宣言リストが空の場合、その直接基底BiBiが独自の基底を持つ場合、これらの規則を再帰的に適用)の検索セットが構築されます。構築された後、直接基底の検索セットはCの検索セットに次のようにマージされます。
  • Biの宣言セットが空の場合、それは破棄されます。
  • これまで構築されたCの検索セットが空の場合、それはBiの検索セットで置き換えられます。
  • Biの検索セットのすべてのサブオブジェクトが、すでにCの検索セットに追加されたサブオブジェクトの少なくとも1つの基底である場合、Biの検索セットは破棄されます。
  • すでにCの検索セットに追加されたすべてのサブオブジェクトが、Biの検索セットのサブオブジェクトの少なくとも1つの基底である場合、Cの検索セットは破棄され、Biの検索セットで置き換えられます。
  • それ以外の場合、BiCの宣言セットが異なる場合、結果は曖昧なマージになります。Cの新しい検索セットには無効な宣言と、以前にCにマージされBiから導入されたサブオブジェクトの和集合が含まれます。この無効な検索セットは、後で破棄される場合はエラーにならないことがあります。
  • それ以外の場合、Cの新しい検索セットには共有された宣言セットと、以前にCにマージされBiから導入されたサブオブジェクトの和集合が含まれます。
(C++11以降)
struct X { void f(); };
 
struct B1: virtual X { void f(); };
 
struct B2: virtual X {};
 
struct D : B1, B2
{
    void foo()
    {
        X::f(); // OK, calls X::f (qualified lookup)
        f(); // OK, calls B1::f (unqualified lookup)
    }
};
 
// C++98 rules: B1::f hides X::f, so even though X::f can be reached from D
// through B2, it is not found by name lookup from D.
 
// C++11 rules: lookup set for f in D finds nothing, proceeds to bases
//  lookup set for f in B1 finds B1::f, and is completed
// merge replaces the empty set, now lookup set for f in C has B1::f in B1
//  lookup set for f in B2 finds nothing, proceeds to bases
//    lookup for f in X finds X::f
//  merge replaces the empty set, now lookup set for f in B2 has X::f in X
// merge into C finds that every subobject (X) in the lookup set in B2 is a base
// of every subobject (B1) already merged, so the B2 set is discarded
// C is left with just B1::f found in B1
// (if struct D : B2, B1 was used, then the last merge would *replace* C's 
//  so far merged X::f in X because every subobject already added to C (that is X)
//  would be a base of at least one subobject in the new set (B1), the end
//  result would be the same: lookup set in C holds just B1::f found in B1)
Bの静的メンバ、Bのネスト型、およびBで宣言された列挙子を見つける修飾されていない名前検索は、検査されているクラスの継承ツリーにB型の複数の非仮想基底サブオブジェクトが存在する場合でも、曖昧さはありません。
struct V { int v; };
 
struct B
{
    int a;
    static int s;
    enum { e };
};
 
struct B1 : B, virtual V {};
struct B2 : B, virtual V {};
struct D : B1, B2 {};
 
void f(D& pd)
{
    ++pd.v;       // OK: only one v because only one virtual base subobject
    ++pd.s;       // OK: only one static B::s, even though found in both B1 and B2
    int i = pd.e; // OK: only one enumerator B::e, even though found in both B1 and B2
    ++pd.a;       // error, ambiguous: B::a in B1 and B::a in B2 
}

[編集] フレンド関数の定義

フレンドシップを付与するクラスの本体内で、フレンド関数定義で使用される名前の場合、修飾されていない名前検索はメンバ関数の場合と同じように進行します。クラスの本体外で定義されるフレンド関数で使用される名前の場合、修飾されていない名前検索は、名前空間内の関数の場合と同じように進行します。

int i = 3;                     // found 3rd for f1, found 2nd for f2
 
struct X
{
    static const int i = 2;    // found 2nd for f1, never found for f2
 
    friend void f1(int x)
    {
        // int i;              // found 1st
        i = x;                 // finds and modifies X::i
    }
 
    friend int f2();
 
    // static const int i = 2; // found 2nd for f1 anywhere in class scope
};
 
void f2(int x)
{
    // int i;                  // found 1st
    i = x;                     // finds and modifies ::i
}

[編集] フレンド関数の宣言

別のクラスのメンバ関数にフレンドシップを与えるフレンド関数の宣言のデクレレータで使用される名前の場合、その名前がデクレレータ識別子のテンプレート引数の一部でない場合、修飾されていない検索はまずメンバ関数のクラスの全スコープを調べます。そのスコープで見つからなかった場合(または名前がデクレレータ識別子のテンプレート引数の一部である場合)、検索はフレンドシップを付与するクラスのメンバ関数として続行されます。

template<class T>
struct S;
 
// the class whose member functions are friended
struct A
{ 
    typedef int AT;
 
    void f1(AT);
    void f2(float);
 
    template<class T>
    void f3();
 
    void f4(S<AT>);
};
 
// the class that is granting friendship for f1, f2 and f3
struct B
{
    typedef char AT;
    typedef float BT;
 
    friend void A::f1(AT);    // lookup for AT finds A::AT (AT found in A)
    friend void A::f2(BT);    // lookup for BT finds B::BT (BT not found in A)
    friend void A::f3<AT>();  // lookup for AT finds B::AT (no lookup in A, because
                              //     AT is in the declarator identifier A::f3<AT>)
};
 
// the class template that is granting friendship for f4
template<class AT>
struct C
{
    friend void A::f4(S<AT>); // lookup for AT finds A::AT
                              // (AT is not in the declarator identifier A::f4)
};

[編集] デフォルト引数

関数宣言のデフォルト引数で使用される名前、またはコンストラクタのメンバ初期化子部分で使用される名前の場合、囲むブロック、クラス、または名前空間スコープが検索される前に、まず関数パラメータ名が見つかります。

class X
{
    int a, b, i, j;
public:
    const int& r;
 
    X(int i): r(a),      // initializes X::r to refer to X::a
              b(i),      // initializes X::b to the value of the parameter i
              i(i),      // initializes X::i to the value of the parameter i
              j(this->i) // initializes X::j to the value of X::i
    {}
};
 
int a;
int f(int a, int b = a); // error: lookup for a finds the parameter a, not ::a
                         // and parameters are not allowed as default arguments

[編集] 静的データメンバの定義

静的データメンバの定義で使用される名前の場合、検索はメンバ関数の定義で使用される名前の場合と同じように進行します。

struct X
{
    static int x;
    static const int n = 1; // found 1st
};
 
int n = 2;                  // found 2nd
int X::x = n;               // finds X::n, sets X::x to 1, not 2

[編集] 列挙子宣言

列挙子宣言の初期化部分で使用される名前の場合、同じ列挙内の以前に宣言された列挙子が、修飾されていない名前検索が囲むブロック、クラス、または名前空間スコープの検索に進む前に、まず見つかります。

const int RED = 7;
 
enum class color
{
    RED,
    GREEN = RED + 2, // RED finds color::RED, not ::RED, so GREEN = 2
    BLUE = ::RED + 4 // qualified lookup finds ::RED, BLUE = 11
};

[編集] 関数tryブロックのハンドラ

関数tryブロックハンドラで使用される名前の場合、検索は、関数の本体の最も外側のブロックの先頭で使用される名前の場合と同じように進行します(特に、関数パラメータは可視ですが、その最も外側のブロックで宣言された名前は可視ではありません)。

int n = 3;          // found 3rd
int f(int n = 2)    // found 2nd
 
try
{
    int n = -1;     // never found
}
catch(...)
{
    // int n = 1;   // found 1st
    assert(n == 2); // loookup for n finds function parameter f
    throw;
}

[編集] オーバーロードされた演算子

式で使用される演算子(例: a + bでのoperator+)の検索規則は、明示的な関数呼び出し式(例: operator+(a, b))で使用される演算子とはわずかに異なります。式を解析する際、非メンバ演算子オーバーロードとメンバ演算子オーバーロード(両方の形式が許可される演算子の場合)の2つの別個の検索が実行されます。これらのセットは、オーバーロード解決で説明されているように、組み込み演算子オーバーロードと対等な立場でマージされます。明示的な関数呼び出し構文が使用される場合、通常の修飾されていない名前検索が実行されます。

struct A {};
void operator+(A, A);  // user-defined non-member operator+
 
struct B
{
    void operator+(B); // user-defined member operator+
    void f();
};
 
A a;
 
void B::f() // definition of a member function of B
{
    operator+(a, a); // error: regular name lookup from a member function
                     // finds the declaration of operator+ in the scope of B
                     // and stops there, never reaching the global scope
 
    a + a; // OK: member lookup finds B::operator+, non-member lookup
           // finds ::operator+(A, A), overload resolution selects ::operator+(A, A)
}

[編集] テンプレート定義

テンプレート定義で使用される非依存名の場合、テンプレート定義が検査されるときに修飾されていない名前検索が行われます。その時点での宣言へのバインディングは、インスタンテーションの時点での可視な宣言の影響を受けません。依存名がテンプレート定義で使用される場合、検索はテンプレート引数が判明するまで延期されます。その時点で、ADLは、テンプレート定義コンテキストとテンプレートインスタンテーションコンテキストの両方から可視な(外部リンケージを持つ(C++11まで))関数宣言を調べます。一方、非ADL検索は、テンプレート定義コンテキストから可視な(外部リンケージを持つ(C++11まで))関数宣言のみを調べます(つまり、ADLを介さない限り、テンプレート定義後に新しい関数宣言を追加しても可視になりません)。ADL検索で調べられる名前空間にある、別の翻訳単位で宣言された、より良いマッチがある場合、またはそれらの翻訳単位を調べた場合に曖昧になったであろう検索の場合、動作は未定義です。いずれの場合も、基底クラスがテンプレートパラメータに依存する場合、そのスコープは修飾されていない名前検索(定義時もインスタンテーション時も)では調べられません。

void f(char); // first declaration of f
 
template<class T> 
void g(T t)
{
    f(1);    // non-dependent name: lookup finds ::f(char) and binds it now
    f(T(1)); // dependent name: lookup postponed
    f(t);    // dependent name: lookup postponed
//  dd++;    // non-dependent name: lookup finds no declaration
}
 
enum E { e };
void f(E);   // second declaration of f
void f(int); // third declaration of f
double dd;
 
void h()
{
    g(e);  // instantiates g<E>, at which point
           // the second and the third uses of the name 'f'
           // are looked up and find ::f(char) (by lookup) and ::f(E) (by ADL)
           // then overload resolution chooses ::f(E).
           // This calls f(char), then f(E) twice
 
    g(32); // instantiates g<int>, at which point
           // the second and the third uses of the name 'f'
           // are looked up and find ::f(char) only
           // then overload resolution chooses ::f(char)
           // This calls f(char) three times
}
 
typedef double A;
 
template<class T>
class B
{
    typedef int A;
};
 
template<class T>
struct X : B<T>
{
    A a; // lookup for A finds ::A (double), not B<T>::A
};

注: この規則の理由と影響については、依存名の検索規則を参照してください。

[編集] テンプレート名

[編集] クラステンプレートのメンバ(テンプレート外)

[編集] 不具合報告

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
CWG 490 C++98 フレンドのテンプレート引数内の
メンバ関数宣言は検索されませんでした
メンバ関数のクラスのスコープで
名前のみを除外
フレンドの
デクレレータ識別子のテンプレート引数
CWG 514 C++98 名前空間で
使用された未修飾名は、まずそのスコープで検索されました。
名前空間外で
名前空間変数メンバを定義するために使用された
未修飾名は、まずその名前空間で検索されます。

[編集] 参考文献

  • C++23標準 (ISO/IEC 14882:2024)
  • 6.5 名前検索 [basic.lookup] (p: 44-45)
  • 6.5.2 メンバ名検索 [class.member.lookup] (p: 45-47)
  • 13.8 名前解決 [temp.res] (p: 399-403)
  • C++20 standard (ISO/IEC 14882:2020)
  • 6.5 名前検索 [basic.lookup] (p: 38-50)
  • 11.8 メンバ名検索 [class.member.lookup] (p: 283-285)
  • 13.8 名前解決 [temp.res] (p: 385-400)
  • C++17 standard (ISO/IEC 14882:2017)
  • 6.4 名前検索 [basic.lookup] (p: 50-63)
  • 13.2 メンバ名検索 [class.member.lookup] (p: 259-262)
  • 17.6 名前解決 [temp.res] (p: 375-378)
  • C++14 standard (ISO/IEC 14882:2014)
  • 3.4 名前検索 [basic.lookup] (p: 42-56)
  • 10.2 メンバ名検索 [class.member.lookup] (p: 233-236)
  • 14.6 名前解決 [temp.res] (p: 346-359)
  • C++11 standard (ISO/IEC 14882:2011)
  • 3.4 名前検索 [basic.lookup]
  • 10.2 メンバ名検索 [class.member.lookup]
  • 14.6 名前解決 [temp.res]
  • C++98 標準 (ISO/IEC 14882:1998)
  • 3.4 名前検索 [basic.lookup]
  • 10.2 メンバ名検索 [class.member.lookup]
  • 14.6 名前解決 [temp.res]

[編集] 関連項目

English 日本語 中文(简体) 中文(繁體)