First things first: I'm using C++17 and would be fine with using Boost::Hana, since I'm using it anyway in my code.
I'm trying to emulate explicit class template instantiation (i.e., all members' definitions are instantiated) by using implicit class template instantiation (which by default does not instantiate member definitions) in the file that defines the class template. If this sounds strange, see "Why would anybody do this?" below for why I think this might be a solution to my actual problem.
The Situation
This is the declaration of my template to be instantiated, in mytemplate.hpp
:
template<class T>
class MyTemplate {
public:
void foo();
};
And this is its definition in mytemplate.cpp
:
#include "mytemplate.hpp"
template<class T>
void
MyTemplate<T>::foo() {}
Forcing complete Implicit Instantiation
To make sure that for some type Whatever
the definition of all of MyTemplate<Whatever>
's members (in this example: MyTemplate<Whatever>::foo()
) is instantiated, I think I need to create a situation, at namespace scope, where for every member of MyTemplate<Whatever>
, it holds that:
the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program
(C++17 standard, 17.7.1.1)
My idea was to use inheritance: If a class Instantiator
derives from MyTemplate<Whatever>
, the definition of all members of Instantiator
must be part of the object file, whether they are used or not, because Instantiator
is not a template - or so I thought. This would then of course also require the class template's member to be instantiated.
Consider this modified mytemplate.cpp
:
#include "mytemplate.hpp"
template<class T>
void
MyTemplate<T>::foo() {}
class Instantiator : public MyTemplate<int> {};
Compiling it does not yield any symbols:
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
How can that be? Why is Instantiator
(and its member) not part of the output?
Do you see any other way to force instantiation of every member of MyTemplate<Whatever>
?
Why would anybody do this?
Somewhere outside of mytemplate.{hpp,cpp}
, I have a list of classes, wrapped into a tuple, like this:
using MyClassList = std::tuple<int, char, bool>;
Now I want to instantiate the definition of MyTemplate
(and all its members) for all classes that are template parameters of MyClassList
- without writing this manually. Basically, if I change the definition of MyClassList
, I don't want to touch mytemplate.{hpp,cpp}
. Thus, I can't use explicit instantiation. I also don't want to include mytemplate.cpp
everywhere that it's used, because the size of my compilation units seems to be problematic already.
Obviously, this means that I can't use the above derived-class trick verbatim, because I would need to manually list all the derived classes, but that problem should be solveable with a recursive class template.