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

StackOverflow https://stackoverflow.com//questions/12681622

  •  12-12-2019
  •  | 
  •  

Вопрос

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

спец.ч:

#include <iostream>

class A
{
public:
    template<typename T>
    T test(const std::string& a)
    {
        std::cout << "DEFAULT CALLED WITH " << a << "\n";
        return T();
    }
};

другое.cpp:

#include "spec.h"

template<>
float A::test<float>(const std::string& a)
{
    std::cout << "SPECIAL CALLED WITH " << a << "\n";
    return float();
}

спец.cpp:

#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 и прямым использованием объектного файла?:-)

Спасибо!

Это было полезно?

Решение

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

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

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

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

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

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

Другие советы

Ответ Бена Voigt является правильным, но я хочу добавить немного к нему.

Вы по сути, получаете две разные версии функции, один в ord.o и один в SPEC.O (сгенерировано встроенным шаблоном).Линкер предназначен для выбора одного и только одного, что делает предположение, что они оба идентичны как стандартные требует.В первом случае компоновщик будет тянуть только определение из библиотеки, если символ уже не определен.Поскольку он определен в SPEC.O Определение библиотеки не используется.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top