Следующий код не генерирует компиляцию / ошибку компоновщика / предупреждение:
// A.h
#include<iostream>
struct A
{
template<typename T>
static void foo (T t)
{
std::cout << "A::foo(T)\n";
}
};
void other ();
// main.cpp
#include"A.h"int main ()
{
A::foo(4.7);
other();
}
// other.cpp
#include"A.h"template<>
void A::foo (double d)
{
cout << "A::foo(double)\n";
}
int other ()
{
A::foo(4.7);
}
Результат на удивление:
A::foo(T)
A::foo(double)
Почему компилятор не может подобрать правильный A::foo(double)
в случае main.cpp
?
Согласитесь, что, как и ожидалось, проблема не возникает, если в A.h
как ниже:
template<> void A::foo (double);
Но это не проблема, потому что во время компиляции компилятор имеет специализированную версию.
Кроме того, имеет 2 разные версии одной и той же функции и Неопределенное поведение ?
Все явные объявления специализации должны быть видимый во время создания шаблона. Поскольку ваше явное объявление специализации для A::foo<double>
видна в одной единице перевода, но не в другой, программа плохо сформирована.
(На практике компилятор будет создавать основной шаблон в main.cpp
и явно специализированный в other.cpp
, Это все равно будет нарушением ОДР.)
main.cpp
не может видеть код внутри other.cpp
, Шаблонные специализации имеют файловую область.
Почему компилятор не может подобрать правильный A :: foo (double) в случае main.cpp?
Проблема состоит в том, что в отдельной модели компиляции без объявления, доступного в заголовке, компилятор, возможно, не будет знать, существует ли специализация в каком-либо модуле перевода, который позже будет связан, или ему нужно создать экземпляр шаблона. Решение на языке состоит в том, что отсутствие объявления означает, что нет никакой специализации шаблона вручную, и, следовательно, компилятор должен генерировать его сейчас.
имеет 2 разные версии одной и той же функции неопределенного поведения?
Да, это. Независимо от того, была ли одна из специализаций сгенерирована автоматически или нет, фактом является то, что она является неопределенным поведением, поскольку является нарушением правила единого определения (существует несколько определений одного и того же символа).