Перво-наперво: я использую C ++ 17 и все будет в порядке с Boost :: Hana, так как я все равно использую его в своем коде.
Я пытаюсь эмулировать явное создание экземпляра шаблона класса (то есть все определения членов создаются) с помощью неявного создания экземпляра шаблона класса (который по умолчанию не создает определения членов) в файле, который определяет шаблон класса. Если это звучит странно, см. «Зачем кому-то делать это?» ниже, почему я думаю, что это может быть решением моей реальной проблемы.
Ситуация
Это объявление моего шаблона для создания экземпляра в mytemplate.hpp
:
template<class T>
class MyTemplate {
public:
void foo();
};
И это его определение в mytemplate.cpp
:
#include "mytemplate.hpp"
template<class T>
void
MyTemplate<T>::foo() {}
Принудительное завершение неявного создания экземпляра
Чтобы убедиться, что для некоторого типа Whatever
определено определение всех членов MyTemplate<Whatever>
(в этом примере: MyTemplate<Whatever>::foo()
), я думаю, что мне нужно создать ситуацию в области пространства имен, где для каждого члена MyTemplate<Whatever>
он гласит:
специализация указана в контексте
это требует полностью определенного типа объекта или когда полнота типа класса влияет на семантику
программы
(стандарт C ++ 17, 17.7.1.1)
Моя идея заключалась в использовании наследования: если класс Instantiator
наследуется от MyTemplate<Whatever>
, определение всех членов Instantiator
должно быть частью объектного файла, независимо от того, используются они или нет, потому что Instantiator
это не шаблон - или я так думал. Тогда это, конечно, также потребует создания экземпляра шаблона класса.
Считайте, что это изменено mytemplate.cpp
:
#include "mytemplate.hpp"
template<class T>
void
MyTemplate<T>::foo() {}
class Instantiator : public MyTemplate<int> {};
Компиляция не дает любых символов:
me@mymachine ~/some/dir $ /usr/bin/g++-7 -g -std=c++17 -o mytemplate.cpp.o -c mytemplate.cpp
me@mymachine ~/some/dir $ nm -a mytemplate.cpp.o
0000000000000000 b .bss
0000000000000000 n .comment
0000000000000000 d .data
0000000000000000 N .debug_abbrev
0000000000000000 N .debug_aranges
0000000000000000 N .debug_info
0000000000000000 N .debug_line
0000000000000000 N .debug_str
0000000000000000 a mytemplate.cpp
0000000000000000 n .note.GNU-stack
0000000000000000 t .text
Как это может быть? Почему Instantiator
(и его член) не является частью вывода?
Видите ли вы какой-либо другой способ заставить инстанцировать каждого члена MyTemplate<Whatever>
?
Зачем кому-то это делать?
Где-то за пределами mytemplate.{hpp,cpp}
у меня есть список классов, завернутый в кортеж, например:
using MyClassList = std::tuple<int, char, bool>;
Теперь я хочу создать экземпляр определения MyTemplate
(и всех его членов) для всех классов, которые являются параметрами шаблона MyClassList
- без написания этого вручную. По сути, если я изменю определение MyClassList
, я не хочу касаться mytemplate.{hpp,cpp}
. Таким образом, я не могу использовать явную реализацию. Я также не хочу включать mytemplate.cpp
везде, где он используется, потому что размер моих модулей компиляции уже кажется проблематичным.
Очевидно, это означает, что я не могу использовать приведенный выше дословный трюк производного класса, потому что мне нужно было бы вручную перечислить все производные классы, но эту проблему следует решить с помощью рекурсивного шаблона класса.