G CC на самом деле не «создает» или «компилирует» шаблон базовой функции. Если бы это было так, у вас были бы две скомпилированные функции с одинаковым именем и списком параметров. Как отметил @Raymond Chen в комментариях, G CC разрешено, но не обязательно, чтобы вызывать ошибку для шаблонов, которые не имеют действительного экземпляра.
Например:
template<
typename T/*the desired type*/,
typename/*the source type*/ Y
> T integral_cast(const Y& y)
{
static_assert(sizeof(Y) == 1);
};
Не вызовет ошибки в приведенном вами примере (потому что он имеет действующий экземпляр и не создается).
Я подозреваю, что G CC просто нужно заменить типы в базовый шаблон для разрешения перегрузки, поэтому на самом деле ему просто нужно объявление , а не определение .
Вы можете получить желаемое поведение, используя удаленное определение:
template<
typename T/*the desired type*/,
typename/*the source type*/ Y
> T integral_cast(const Y& y) = delete;