В следующем коде 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
"в контексте всего постфиксного выражения" и "в точке определения шаблона".
Цитата из С++ Рабочий проект стандарта N3242 = 11-0012 (февраль 2011):
3.4.5 Доступ к члену класса [basic.lookup.classref]
Если id-выражение в доступе члена класса является квалифицированным идентификатором формы
class-name-or-namespace-name::...
имя класса или имя пространства имен, следующих за оператором
.
или->
, рассматривается как в контексте целое postfix-expression и в объем класса выражения объекта. Если имя найдено только в область действия класса выражения объекта, имя должно ссылаться на имя класса. Если имя найдено только в контексте всего постфиксного выражения, имя должно ссылаться на имя класса или имя пространства имен. Если имя найдено в обоих контекстах, имя класса или имя пространства имен должно относиться к тому же юридическое лицо.14.6.4 Зависимое разрешение имени [temp.dep.res]
При разрешении зависимых имен учитываются имена из следующих источников:
- Объявления, которые видны в точке определения шаблона.
- объявления из пространств имен, связанных с типами аргументов функции как из контекст контекста (14.6.4.1) и контекст определения.