Использование шаблона, прежде чем он станет специализированным?

Я узнал, что вы можете специализировать шаблон после это первое использование, если вы используете его с помощью шаблона оболочки. Простой пример:

#include <iostream>

template<typename T>
const char* templateImpl();

template<typename T>
const char* templateGetter() { return templateImpl<T>(); }

struct S{};

int main(){ std::cout << templateGetter<S>() << std::endl; return 0; }

template<>
const char* templateImpl<S>(){ return "S"; }

Это работает с каждым компилятором — я не удивлен, что MSVC компилирует его, так как он обрабатывает шаблоны по-разному, но GCC и clang также позволяют это. Я думал, что стандарт требует, чтобы специализация произошла до первого использования, что в данном случае означало бы перед основным, и ожидал, что они сообщат об ошибке.

Я что-то пропустил, соответствует ли этот стандарт стандарту?

Чтобы уточнить, если я изменю templateGetter<S> в templateImpl<S> в основном, программа не будет компилироваться с сообщением об ошибке, которое я ожидаю от этого:

main.cpp: 14: 29: ошибка: специализация ‘const char * templateImpl ()
[с T = S] ‘после создания

14

Решение

Вам повезло (не) Это плохо сформированный NDR.

[Temp.expl.spec] / 6-7:

6 Если шаблон, шаблон элемента или элемент шаблона класса
явно специализированный тогда эта специализация должна быть объявлена
до первого использования этой специализации, что вызвало бы
неявное создание экземпляра в каждой единице перевода в
какое такое использование происходит
; Диагностика не требуется. […]

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

p7 здесь не очень полезен, но я не могу удержаться от цитирования 🙂

Инстанцирование templateGetter<S> вызывает неявное создание декларации templateImpl<S>, Вы не видели ошибку в своем коде, потому что многие реализации любят откладывать создание экземпляров шаблона до конца модуля перевода, когда это возможно, что является допустимым методом реализации. (Я не собираюсь цитировать стандартное здесь, но вы обнаружите, что специализации шаблонов функций имеют дополнительную точку создания в конце модуля перевода.)

дающий templateGetter выведенный тип возврата будет вызывать раннее создание его тела:

template<typename T>
auto templateGetter() { return templateImpl<T>(); }

а также вуаля:

+ g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
main.cpp:14:29: error: specialization of 'const char* templateImpl() [with T = S]' after instantiation
const char* templateImpl<S>(){ return "S"; }
^
+ clang++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
main.cpp:14:13: error: explicit specialization of 'templateImpl<S>' after instantiation
const char* templateImpl<S>(){ return "S"; }
^
main.cpp:7:32: note: implicit instantiation first required here
auto templateGetter() { return templateImpl<T>(); }
^
1 error generated.
10

Другие решения

Я думаю, что это законно. Цитируя N4140, [temp.point]:

Для специализации шаблона функции, … если специализация
создается неявно, потому что на него ссылаются из другого
специализация шаблона и контекст, на который он ссылается
зависит от параметра шаблона, точка создания
специализация является точкой воплощения вложения
специализация. В противном случае, точка инстанции для такого
специализация сразу следует за объявлением области имен пространства или
определение, которое относится к специализации.

Затем в [temp.fct.spec]:

Функция, созданная из шаблона функции, называется функцией
специализация шаблона; так явная специализация
шаблон функции. …

Другими словами, ошибка на самом деле не произойдет, пока templateGetter() и впоследствии специализация templateImpl создаются, как вы ожидаете, шаблоны будут работать.

1

По вопросам рекламы [email protected]