Заставить неявную реализацию шаблона класса включить все определения - PullRequest
0 голосов
/ 16 мая 2018

Перво-наперво: я использую 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 везде, где он используется, потому что размер моих модулей компиляции уже кажется проблематичным.

Очевидно, это означает, что я не могу использовать приведенный выше дословный трюк производного класса, потому что мне нужно было бы вручную перечислить все производные классы, но эту проблему следует решить с помощью рекурсивного шаблона класса.

...