У меня есть класс-шаблон NB::B<T>
, производный от класса-шаблона NA::A
в пространстве имен. act<T>
— это функция шаблона, вызывающая функцию add_ref
для экземпляра своего аргумента шаблона. В частности, act<NB::B<int>>
хочет найти add_ref
, определенное в пространстве имен базы NB::B
, используя ADL. Полный пример следующий:
template<class T>
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 <class T>
struct B: NA::A { };
typedef B<int> Bi;
// using NA::add_ref; // fixes the problem
}
int main()
{
act<NB::Bi>();
}
Это нормально компилируется в gcc
(4.7.0). И в Comeau
онлайн. Однако clang
(3.1) терпит неудачу:
a.cpp:4:3: error: use of undeclared identifier 'add_ref'
При этом стандарт гласит:
3.4.2/2 …
— Если T является идентификатором шаблона, связанные с ним пространства имен и классы являются пространством имен, в котором определен шаблон; для шаблонов-членов — класс шаблона-члена; пространства имен и классы, связанные с типами аргументов шаблона, предоставленными для параметров типа шаблона (исключая параметры шаблона шаблона); пространства имен, в которых определены любые аргументы шаблона шаблона; и классы, в которых определены любые шаблоны элементов, используемые в качестве аргументов шаблона шаблона.
Удивительно, но базы шаблонов не указаны как пути к связанным пространствам имен. Таким образом, поведение clang
кажется правильным. А Comeau
и gcc
принимают неверную программу.
В то же время 3.4.2/3
утверждает, что using
в пространствах имен аргументов не действуют:
При рассмотрении связанного пространства имен поиск аналогичен поиску, выполняемому, когда связанное пространство имен используется в качестве квалификатора (3.4.3.2), за исключением того, что:
— Любые директивы использования в связанном пространстве имен игнорируются.
Но когда я раскомментирую строку using NA::add_ref
, clang
с радостью скомпилирует тест.
Чтобы представить мой пример в практической перспективе, вы можете подумать, что act
был методом boost::intrusive_ptr
, add_ref(A*)
был intrusive_ptr_add_ref(CBase*)
, а B
был неким шаблоном, производным от базы CBase
.
В связи с этим у меня несколько вопросов:
Прав ли я в том, что
clang
правильно отвергают мою тестовую программу, аgcc
иComeau
не соответствуют стандарту?Есть ли причина, по которой стандарт определяет такое непрактичное поведение (запрещает базы классов шаблонов в качестве связанных пространств имен)?
Является ли
clang
неправильным принятие моей тестовой программы с директивойusing NA::add_ref
на основании3.4.2/3
?Должен ли я сообщить об ошибке? :)
P.S. Я прочитал часто задаваемые вопросы о совместимости языков и не нашел там ответа.
NB::B<int>
является классом (который оказывается специализацией шаблона), а не шаблоном. (Правила IIUC заключаются в том, что пространства имен, связанные с шаблоном, специализацией которого является тип, добавляются к пространствам имен, связанным с классом.) - person Luc Danton   schedule 23.07.2012add_ref
по умолчанию, которая всегда будет лучше соответствовать, чем связанное пространство имен прямой базы? - person pmr   schedule 23.07.2012class
иtemplate-id
) относятся к классамtemplate-id
. - person Nicht Verstehen   schedule 24.07.2012add_ref
функции не находятся в области вызова изintrusive_ptr.hpp
. - person Nicht Verstehen   schedule 24.07.2012act
нет функцииadd_ref
. Шаблон в пространстве именact()
может лучше соответствовать и будет выбран вместо функции, связанной с базой. - person pmr   schedule 24.07.2012using NA::add_ref;
не является директивой использования, это декларация использования, поэтому 3.4.2/3 не применяется. Директива использования выглядит какusing namespace NA;
. - person Richard Smith   schedule 31.07.2012