2

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.

Lukas Barth
  • 2,734
  • 18
  • 43
  • 1
    I mean really, you would say yourself a lot of pain if you would define `foo` in the header :) Any specific reason not to? Just curious – Rakete1111 May 16 '18 at 14:55
  • 2
    See [this](https://stackoverflow.com/q/7398964/2069064). There's just no programmatic way of doing multiple instantiations besides the preprocessor. – Barry May 16 '18 at 14:58

0 Answers0