次のコードでは、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>::N
N
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) と定義コンテキストの両方からの関数引数の型に関連付けられた名前空間からの宣言。