функция специализированного члена теряется после связывания через ар

Рассмотрим следующий минимальный пример, который воспроизводит проблему в гораздо большем проекте:

#include <iostream>

class A
{
public:
template<typename T>
T test(const std::string& a)
{
std::cout << "DEFAULT CALLED WITH " << a << "\n";
return T();
}
};
#include "spec.h"
template<>
float A::test<float>(const std::string& a)
{
std::cout << "SPECIAL CALLED WITH " << a << "\n";
return float();
}
#include <iostream>
#include "spec.h"
int main()
{
A a;
a.test<int>("int");
a.test<float>("float");
return 0;
}
$ make
rm -f *.o lib.a output
clang++ -g other.cpp -c
clang++ -g spec.cpp -c
ar cr lib.a other.o
clang++ -g -o output lib.a spec.o
rm -f *.o output2
clang++ -g other.cpp -c
clang++ -g spec.cpp -c
clang++ -g -o output2 other.o spec.o

$ ./output
DEFAULT CALLED WITH int
DEFAULT CALLED WITH float

$ ./output2
DEFAULT CALLED WITH int
SPECIAL CALLED WITH float

Почему это происходит? это как-то раздевается? В чем разница между lib.a и прямым использованием объектного файла? 🙂

Спасибо!

3

Решение

Из раздела 14.7.3p6:

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

Ваша программа неверна, потому что вы использовали специализацию в spec.cpp, не объявив ее сначала в этом модуле перевода. Или, как говорится в следующем абзаце:

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

При написании специализации
будьте осторожны с его местоположением;
или сделать его компиляцией
будет такое испытание
как разжечь его самосожжение.

за что я голосую за самый крутой параграф лимерик во всем стандарте.

8

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

Ответ бен фойгта правильно, но я хочу добавить немного к этому.

По сути, вы получаете две разные версии функции, одну в other.o и одну в spec.o (генерируемую встроенным шаблоном). Линкер предназначен для выбора одного и только одного, исходя из предположения, что они оба идентичны, как того требует стандарт. В первом случае компоновщик извлекает определение из библиотеки, только если символ еще не определен. Поскольку это определено в spec.o, определение библиотеки не используется.

2

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

1