Аргумент -зависимый поиск по базе класса шаблона

У меня есть класс шаблона NB::B, производный от класса шаблона, отличного от -, NA::Aв пространстве имен. act— это функция шаблона, вызывающая функцию add_refдля экземпляра своего аргумента шаблона. В частности, act>хочет найти add_ref, определенный в пространстве имен базы NB::B, используя ADL. Полный пример следующий:

template
void act() {
  T* p = 0;
  add_ref(p); // the failing line
}

namespace NA
{
  struct A { };

  // I want ADL to find this:
  void add_ref(A* p) {
  }
}

namespace NB
{
  // template class with non-template base
  template 
  struct B: NA::A { };

  typedef B Bi;

  // using NA::add_ref; // fixes the problem
}

int main()
{
  act();
}

Это нормально компилируется вgcc(4.7.0 ). И в Comeauонлайн. Однакоclang(3.1 )не работает:

a.cpp:4:3: error: use of undeclared identifier 'add_ref'

В то же время стандарт гласит:

3.4.2/2 …

— If T is a template-id, its associated namespaces and classes are the namespace in which the template is defined; for member templates, the member template’s class; the namespaces and classes associated with the types of the template arguments provided for template type parameters (excluding template template parameters); the namespaces in which any template template arguments are defined; and the classes in which any member templates used as template template arguments are defined.

Удивительно, но базы шаблонов не указаны как пути к связанным пространствам имен. Таким образом, поведение clangкажется правильным. А Comeauи gccпринимают неверную программу.

В то же время 3.4.2/3утверждает, что usingв пространствах имен аргументов не действуют :

When considering an associated namespace, the lookup is the same as the lookup performed when the associated namespace is used as a qualifier (3.4.3.2) except that:

— Any using-directives in the associated namespace are ignored.

. Но когда я раскомментирую строку using NA::add_refclang, я с удовольствием скомпилирую тест.

Чтобы представить мой пример в практической перспективе, вы можете подумать, что actбыл методом boost::intrusive_ptr, add_ref(A*)был intrusive_ptr_add_ref(CBase*), а Bбыл неким шаблоном, производным от базы CBase.

В связи с этим у меня есть несколько вопросов:

  1. Прав ли я, что clangправильно отвергает мою тестовую программу, а gccи Comeauне соответствуют стандарту?

  2. Есть ли причина, по которой стандарт определяет такое непрактичное поведение (, как запрет на использование баз классов шаблонов в качестве связанных пространств имен )?

  3. Является ли clangнеправильным принятие моей тестовой программы с директивой using NA::add_refна основании 3.4.2/3?

  4. Должен ли я сообщить об ошибке?:)

P.S. Я прочитал clang FAQ по языковой совместимости и не нашел там ответа.

8
задан Sergey K. 24 July 2012 в 16:29
поделиться