10

次のコードでは、clang 3.0 はを返しますがerror: lookup of 'N' in member access expression is ambiguous、clang 3.4 と gcc 4.8 は両方ともエラーなしでコードを受け入れます。

struct B
{
    struct M
    {
        void f()
        {
        }
    };
};

namespace N
{
    struct M
    {
        void f()
        {
        }
    };
}

template<typename>
struct A : N::M, B::M
{
    typedef B N;
};

struct D : A<int>
{
    A<int> m;
    void f()
    {
        m.N::M::f(); // found class-name 'A<int>::N' (unambiguous)
    }
};

template<typename T>
struct C : A<T>
{
    A<T> m;
    void f()
    {
        m.N::M::f(); // found namespace-name 'N' (ambiguous?)
    }
};

template struct C<int>;

標準を参照した後、 の式に関してどの動作が正しいかは明確ではありませんC<T>::f()

Nはオブジェクト式のクラスのスコープn(依存) と後置式全体のコンテキスト (つまり、関数のスコープ) の両方で検索されるためC<T>::f()、インスタンス化の時点まで検索を遅らせる必要があります。 .

インスタンス化の時点で、名前空間Nと typedef の両方が見つかった場合、ルックアップはあいまいになりますA<T>::N。の宣言はN、 の宣言によって非表示にされていない場合にのみ表示されA<T>::Nます。

問題は、「後置式全体のコンテキストで」および「テンプレートの定義の時点で」検索するときに、名前空間Nが typedef によって隠されていると見なされるべきかどうかです。A<T>::NN

C++ Working Draft standard N3242=11-0012 (2011 年 2 月) から引用:

3.4.5 クラスメンバーアクセス [basic.lookup.classref]

クラス メンバー アクセスの id-expression がフォームの修飾 ID である場合

class-name-or-namespace-name::...

.or->演算子に続く class-name-or-namespace-nameは、postfix-expression 全体のコンテキストとオブジェクト式のクラスのスコープの両方で検索されます。名前がオブジェクト式のクラスのスコープでのみ見つかった場合、その名前はクラス名を参照する必要があります。名前が接尾辞式全体のコンテキストでのみ見つかった場合、その名前はクラス名または名前空間名を参照する必要があります。名前が両方のコンテキストで見つかった場合、class-name-or-namespace-name は同じエンティティを参照する必要があります。

14.6.4 依存名解決 [temp.dep.res]

従属名の解決では、次のソースからの名前が考慮されます。

テンプレートの定義時に表示される宣言。

— インスタンス化コンテキスト (14.6.4.1) と定義コンテキストの両方からの関数引数の型に関連付けられた名前空間からの宣言。

4

1 に答える 1

5

これは C++11 で変更されたものです。引用するテキストは C++03 のものです。C++11 より前では、両方のルックアップが使用されていたため、これはあいまいであり、異なる名前が見つかった場合はエラーでした。C++11 では、テキストは次のとおりです。

クラス メンバー アクセスの id-expression が、クラス名または名前空間名::... の形式の修飾 ID である場合、. の後にクラス名または名前空間名が続きます。or -> 演算子は最初にオブジェクト式のクラスで検索され、見つかった場合はその名前が使用されます。それ以外の場合は、postfix-expression 全体のコンテキストで検索されます。[注: 3.4.3 を参照してください。これは、:: の前の名前の検索について説明しています。これは、型または名前空間の名前のみを検索します。—終わりのメモ]

基本的に、これはクラス スコープ内のルックアップに特権を与え、名前が見つかった場合は他のルックアップを実行しません。

これが標準の古いバージョンのテンプレートにのみ影響を与えた理由について: (ここで何かを確認するのは難しい) 非テンプレートの場合、ポストフィックス全体のコンテキストでのルックアップが原因であると思います-expression もtypedef基本クラスで を検索するため、両方のルックアップが同じエンティティに解決されます。テンプレートの場合、postfix-expression 全体のコンテキストでの検索では、依存する基本クラスは考慮されず、名前空間のみが検索されます N。ただし、 のインスタンス化後C、クラスのスコープ内のルックアップでtypedef. 2 つの検索で異なるエンティティが検出されるため、名前のバインディングはあいまいです。

于 2013-08-13T11:32:56.060 に答える