ошибка clang «явное создание экземпляра не ссылается на шаблон функции» в нескольких пространствах имен

#c #templates #gcc #namespaces #clang

#c #шаблоны #gcc #пространства имен #clang

Вопрос:

Я пытаюсь повторно использовать существующие шаблонные функции из пространства имен в моем собственном пространстве имен и явно создавать их экземпляры из соображений покрытия кода.

Следующий код компилируется с помощью gcc 9.3, но не компилируется с clang 10.0.0

 namespace bar {
    template<typename T>
    T func(T arg){ return arg;};
}

namespace foo {
    using bar::func;
}

template int foo::func<int>(int);

int main()
{ }
  

Посмотреть пример здесь

Если я создаю экземпляр функции шаблона как

 template int bar::func<int>(int);
  

clang также компилируется. Но это не то, что я хочу.

Возможно ли явное создание экземпляра функции шаблона в пространствах имен с помощью clang?

Почему gcc и clang дают разные результаты?

Ответ №1:

Боюсь, вы не можете этого сделать. Clang верен.

[temp.explicit]

2 Синтаксис для явного создания экземпляра:

явное создание экземпляра: 
 объявление шаблона extern opt

4 Если явное создание экземпляра предназначено для класса или класса-члена, детализированный спецификатор типа в объявлении должен включать идентификатор простого шаблона; в противном случае объявление должно быть простым объявлением, список инициализации которого содержит один инициализирующий декларатор, у которого нет инициализатора.

В этом абзаце говорится, что бит после template ключевого слова должен быть как синтаксически, так и семантически допустимым объявлением для чего-либо (и не должен содержать инициализатор, который здесь неуместен). Объявление состоит из нескольких частей, но интерес здесь представляет часть объявления declarator.

Об этом у нас есть следующий абзац

[dcl.значение] (выделение мое)

1 Декларатор содержит ровно один идентификатор декларатора; он называет объявленный идентификатор. Неквалифицированный идентификатор, встречающийся в идентификаторе декларатора, должен быть простым идентификатором, за исключением объявления некоторых специальных функций ([class.ctor], [class.conv], [class.dtor], [over.oper] ) и для объявления специализаций шаблонов или частичных специализаций ([temp.spec]). Когда указан идентификатор декларатора, объявление должно ссылаться на ранее объявленный член класса или пространства имен, на который ссылается квалификатор (или, в случае пространства имен, элемента встроенного набора пространств имен этого пространства имен ([namespace.def] )) или на специализациюиз-за этого; член не должен быть просто введен с помощью объявления using в области класса или пространства имен, назначенного спецификатором вложенного имени идентификатора декларатора.

Поскольку ваш идентификатор декларатора в явном создании экземпляра шаблона есть foo::func , он не соответствует правилу, изложенному в предложении, которое я выделил жирным шрифтом. Это делает вашу попытку явного создания экземпляра некорректной.

GCC также должен был отклонить вашу попытку.