Должна ли следующая программа компилироваться в соответствии со стандартом?

После моего обнаружения несогласованности между MSVC и GCC (возможно, тоже clang) в компиляции и связывании одного и того же кода мне стало любопытно, должна ли эта программа действительно компилировать и связывать и, таким образом, ее ошибка в MSVC (которая сообщает об ошибке компоновщика), или я должен писать его по-разному. Программа состоит из 3 файлов:

C.h

template <typename T>
struct A
{
    void func() {};
};

template <>
void A<int>::func ();

a.cpp:

#include "C.h"
int main()
{
    A<int> x;
    x.func();
}

B.cpp:

#include "C.h"
template <>
void A<int>::func()
{
}

Результирующая ошибка компоновщика из MSVC:

A.obj: ошибка LNK2019: неразрешенный внешний символ "public: void __thiscall A:: func (void)"

Таким образом, в основном он решает не создавать символ из определения, помещенного в B.cpp. То, что заставляет меня сильно подозревать, что это ошибка, заключается в том, что перемещение неспециализированного определения func из определения структуры и даже размещение его выше объявления специализации делает успешную реализацию программы linnking, но я хотел бы быть уверен.

Итак, мой вопрос: должна ли эта программа быть скомпилирована и связана без ошибок с помощью соответствующего компилятора/компоновщика?

Ответ 1

Из стандарта:

© ISO/IEC N4527 14.6.4.1 Точка инстанцирования [temp.point] 1 Для специализации шаблона функции, специализации шаблона функции-члена или специализация для функции-члена или статического члена данных класса шаблон, если специализация неявно создается, потому что она ссылается из другой специализированной специализации и контекст, от которого он ссылается, зависит от параметра шаблона, точкой инстанцирования специализации является точка создание специализированной специализации. В противном случае точка экземпляра для такой специализации сразу следует декларация или определение области пространства имен, которая ссылается на специализация.

В этом случае я думаю, это означает, что в C.h появляется "объявление области видимости". Если это так, то ваш код должен ссылаться на стандартную совместимую цепочку инструментов. Я мог бы неправильно истолковать это...

Ответ 2

У пространств имен есть внутренняя связь. Поскольку спецификация шаблона находится в неназванном пространстве имен, она также имеет внутреннюю связь.

Чтобы решить проблему, поместите шаблон в именованное пространство имен или укажите специализацию как "extern".