Является ли законным объявление ссылочного шаблона в С++ 14 без инициализации основного шаблона ссылки, если он никогда не создается экземпляром?
template<class T>
const T& ref;
template<>
auto ref<int> = 1;
auto x = ref<int>;
Это дает разные результаты для GCC и Clang:
$ g++ -std=c++14 -c ref.cpp
$
$ clang -std=c++14 -c ref.cpp
ref.cpp:2:10: error: declaration of reference variable 'ref' requires an
initializer
const T& ref;
^~~
1 error generated.
Нет смысла инициализировать основной шаблон ссылки, потому что до тех пор, пока он не будет создан, это шаблон, а не ссылка.
Я обнаружил, что могу сделать что-то вроде:
template<class T>
const T& ref = "Meaningless initialization with any value of any type";
template<>
auto ref<int> = 1;
auto x = ref<int>;
потому что, по-видимому, GCC и Clang оба принимают, но игнорируют ссылочный шаблонный инициализатор RHS, если это действительное выражение и основной шаблон ссылки никогда не создаются. И любое выражение любого типа удовлетворяет требованию инициализации Клана.
GCC не требует инициализатора, если первичный шаблон ссылки никогда не создается. Это похоже на правильное поведение "по духу", потому что до тех пор, пока ссылочный шаблон не будет создан, ему не потребуется инициализатор.
Стандарт не является 100% ясным для ссылочных шаблонов. Вот что я могу найти в переменной экземпляра шаблона:
14.7.1
Если спецификация переменных шаблона не была явно создана или явно специализирована, специализация шаблона переменных неявно создается при использовании специализации.
...
Реализация не должна неявно создавать экземпляр... шаблон переменной... который не требует создания экземпляра.
14.7.2
Для встроенных функций Кроме этого, выражение с типами, выведенных из их инициализатора или возвращаемого значения (7.1.6.4),
const
переменные типов литералов, переменные ссылочных типов и специализацией шаблона класса, явные объявлениями инстанцирования имеет эффект подавления неявной Конкретизации сущность, к которой они относятся. [Примечание. Цель состоит в том, что встроенная функция, являющаяся предметом явного объявления создания экземпляра, будет по-прежнему неявно создаваться при использовании odr (3.2), чтобы тело можно было рассматривать для вложения, но это не внерепиксельная копия встроенной функции будет сгенерирована в блоке перевода.14.7.3
Объявление шаблона функции, шаблона класса или шаблона переменной, явно специализированного, предшествует объявлению явной специализации. [ Примечание. Требуется декларация, но не определение шаблона. -End note ].
Изменить для добавления:
Объявление переменной шаблона, объявление шаблона шаблона или объявление шаблона функции не совпадает с объявлением переменной, объявлением класса или объявлением функции соответственно и не подпадают под действие тех же правил. Пока шаблон не будет создан, это всего лишь шаблон.
Шаблоны классов, шаблоны переменных и шаблоны функций могут быть объявлены без предоставления первичного определения, только определений специализации. Следующий код является законным как для Clang, так и для GCC:
// Class
template<class T> class foo; // Declaration, not definition
template<> class foo<int> {}; // Specialization definition
using ifoo = foo<int>; // Specialization instantiation
// Function
template<class T> void bar(T); // Declaration, not definition
template<> void bar(int) {} // Specialization definition
void (*barp)(int) = bar<int>; // Specialization instantiation
// Variable
int j;
template<class T> T* point; // Declaration, not definition
template<> int* point<int> = &j; // Specialization definition
int *k = point<int>; // Specialization instantiation
Поэтому возникает вопрос, почему он должен быть каким-то другим для эталонного шаблона? Почему первичное объявление эталонного шаблона должно быть определением с инициализацией ссылки, если это не относится к каким-либо другим шаблонам?
template<class T> const T& ref; // Declaration, not definition
template<> const int& ref<int> = 1; // Specialization definition
const int& iref = ref<int>; // Specialization instantiation