Проблема bool Factory<Base, Args...>::Registrar<T>::registered
Обратите внимание, что на это значение ссылаются только тогда, когда оно инициализируется:
template <class Base, class... Args>
template <class T>
bool Factory<Base, Args...>::Registrar<T>::registered =
Factory<Base, Args...>::Registrar<T>::registerT();
Теперь, так как это значение не используется в оптимизаторе кода, оно было удалено.Поскольку он был удален, он не инициализирован.Поскольку он не был инициализирован, процесс регистрации не был выполнен.
Это происходит, поскольку вы разбили код на несколько файлов, а его пример был помещен в один источник.
Вы должны сделать что-то, что предотвратитудаление bool Factory<Base, Args...>::Registrar<T>::registered
оптимизатором.
Чтобы доказать мою точку зрения, я создал ваш проект на github на Mac OS.Я запустил этот скрипт:
nm app/Debug/app | awk '{print $NF}' | while read sym
do
c++filt $sym | grep "Factory"
done
Это выводит только то, что:
guard variable for Factory<Animal, int>::data()::s
Factory<Animal, int>::data()
std::__1::unique_ptr<Animal, std::__1::default_delete<Animal> > Factory<Animal, int>::make<int>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int&&)
Factory<Animal, int>::data()::s
Обратите внимание, что нет registered
статических полей или Cat
или Dog
.Все это было удалено компоновщиком.
Сценарий объяснения
nm app/Debug/app
печатает все символы для app
awk '{print $NF}'
фильтра последних столбцов (что обеспечивает искажениеимена) while read sym
зацикливание на искаженных именах c++filt $sym
разделение имен grep "Factory"
показывать только вещи, связанные с фабрикой.
Теперь, когда в cat.cpp
я добавил это:
void dummy()
{
std::cout << Animal::Registrar<Cat>::registered << '\n';
}
И вызвал его в main
Создание "Кошки" работает ("Собака" продолжает терпеть неудачу).
Скрипт после этого печатает:
Factory<Animal, int>::Registrar<Cat>::registered
Factory<Animal, int>::Registrar<Cat>::registerT()
Factory<Animal, int>::Registrar<Cat>::Registrar()
Factory<Animal, int>::Registrar<Cat>::~Registrar()
Factory<Animal, int>::Registrar<Cat>::~Registrar()
Factory<Animal, int>::Registrar<Cat>::~Registrar()
typeinfo for Factory<Animal, int>
typeinfo for Factory<Animal, int>::Registrar<Cat>
typeinfo name for Factory<Animal, int>
typeinfo name for Factory<Animal, int>::Registrar<Cat>
vtable for Factory<Animal, int>::Registrar<Cat>
Factory<Animal, int>::data()::s
Factory<Animal, int>::Registrar<Cat>::registerT()::'lambda'(int)::operator()(int) const
Factory<Animal, int>::Registrar<Cat>::registerT()::'lambda'(int)::operator std::__1::unique_ptr<Animal, std::__1::default_delete<Animal> > (*)(int)() const
Factory<Animal, int>::Registrar<Cat>::registerT()::'lambda'(int)::__invoke(int)
Что является окончательным доказательством того, что я прав.Линкер заметил, что символы, создающие экземпляр шаблона Factory<Base, Args...>::Registrar<T>::registered
, недоступны из main
(есть только круговая зависимость), поэтому он был удален.
Здесь вы можете найти ответ как подойти к этомупроблема в gcc (это не работает в clang - это атрибуты и флаги компоновщика не присутствуют в clang), но, как вы можете видеть, это довольно сложно.