Может ли точка-заявка быть отложена до конца единицы перевода?

Рассмотрим следующий небольшой фрагмент кода:

#include <iostream> 

template<class T> 
int test(); 

int main() 
{     
    std::cout << test<int>() << "\n"; 
} 

// POI for test<int>() should be right here      

template<class T> 
int test() 
{ 
    return 0; 
}

Живой пример, который компилирует и печатает 0 для Clang и g++.

Здесь черновик проекта в момент создания шаблонов функций

14.6.4.1 Точка инстанцирования [temp.point]

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

Vandevoorde и Josuttis могут сказать следующее:

На практике большинство компиляторов откладывают фактическое noninline шаблоны функций до конца единицы перевода. Эта эффективно перемещает POI соответствующего шаблона специализации до конца единицы перевода. Намерение разработчики языка С++ были для этого правильной реализацией техники, но стандарт не делает этого ясно.

Вопрос: являются несоответствия Clang/g++, поскольку они задерживают POI до конца единицы перевода?

Ответ 1

Отчет о дефектах основной рабочей группы 993 был создан для решения этой проблемы:

993. Свобода выполнения экземпляра в конце единицы перевода

Раздел: 14.6.4.1 [temp.point] Статус: С++ 11 Отправитель: John Spicer Дата: 6 марта 2009 г.
[Проголосовали в WP на встрече в марте 2011 г.]

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

Предлагаемая резолюция (январь 2011 года):

Измените 14.6.4.1 [temp.point] пункт 7 следующим образом:

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

Пункт 14.6.4.1/7 в С++ 11 равен 14.6.4.1/8 в N3936:

Специализация шаблона функции, шаблона функции-члена или функции-члена или статической элемент данных шаблона класса может иметь несколько точек инстанцирования внутри единицы перевода и в дополнение к точкам инстанцирования, описанным выше, для любой такой специализации, которая имеет точку инстанцирования внутри единицы перевода, конец единицы перевода также считается точкой конкретизации. Специализация шаблона класса имеет не более одной точки инстанцирования в переводе Блок. Специализация для любого шаблона может иметь точки инстанцирования в нескольких единицах перевода. Если две разные точки инстанцирования дают шаблонную специализацию разных значений в соответствии с одной (3.2), программа плохо сформирована, не требуется диагностика.

Итак, да, допустимо, чтобы реализации задерживали точку создания шаблонов до конца единицы перевода.

Ответ 2

Явная специализация после явного вызова шаблона не будет выполнена при компиляции.

#include <iostream> 

template<class T> 
int test(T y);


int main() 
{     
    std::cout << test<int>(0) << "\n"; 
}

template<class T> 
int test(T y) 
{ 
    return 0; 
}

// POI for test<int>() should be right here      

template<>
int test(int y) 
{ 
    return 2; 
}

Проверьте ошибку компиляции здесь

Compilation error    time: 0 memory: 0 signal:0
prog.cpp:21:15: error: specialization of ‘int test(T) [with T = int]’ after instantiation
int test(int y)