11

Given a template metaprogram (TMP), do C++ compilers produce build statistics that count the number of instantiated classes? Or is there any other way to automatically get this number? So for e.g. the obiquitous factorial

#include <iostream>

template<int N> struct fact { enum { value = N * fact<N-1>::value }; };
template<> struct fact<1> { enum { value = 1 }; };

int main()
{
    const int x = fact<3>::value;
    std::cout << x << "\n";
    return 0;
}

I would like to get back the number 3 (since fact<3>, fact<2>, and fact<1> are instantiated). This example if of course trivial, but whenever you start using e.g. Boost.MPL, compile times really explode, and I'd like to know how much of that is due to hidden class instantiations. My question is primarily for Visual C++, but answers for gcc would also be appreciated.

EDIT: my current very brittle approach for Visual C++ is adding the compile switch from one of Stephan T. Lavavej's videos /d1reportAllClassLayout and doing a grep + word count on the output file, but it (a) increases compile times enormously and (b) the regex is hard to get 100% correct.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304

3 Answers3

8

I made a one-line change to GCC that makes it print out the name of each class template as it instantiates it. You can already call the C++ front-end cc1plus directly without the -quiet flag to get the same for function templates.

I haven't got round to turning that into a proper GCC option yet, it's just a hack on my own source tree. I'm thinking of implementing it as a plugin instead, but it's not near the top of my TODO list.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • +1. I suggested that it should be pretty easy to hack up any open source compiler, but you actually proved it, in the best way possible (by writing a patch that actually does it). – abarnert Jul 10 '12 at 01:19
  • Thanks! What would even be more convenient to have (yes, scope creep coming up!) is a log of all class templates and the number of their instantiations, rather than just the total number or the entire list of all instantiations. Perhaps a perl script to post-process the full build log is what I should be trying. – TemplateRex Jul 10 '12 at 06:11
  • 1
    just pipe the output to `awk -F '<' '{ templates[$1]++ } END { for (t in templates) print t, templates[t] }'` – Jonathan Wakely Jul 10 '12 at 09:11
2

There is, of course, no portable way to do this.

There are hacky ways to do it for most compilers. You already found one for MSVC. For gcc, you can probably use gccxml. Or, for any open source compiler (gcc or clang), it should be pretty simple to add code at the point of instantiation that either keeps count, or logs something that you can filter after the compile is done.

For Clang/LLVM, you can just build a plugin that hooks the instantiation, which is a lot cleaner, but probably actually more work.

A build with debug symbols, no optimization, and no stripping might end up with the mangled names of every instantiation, which you can grep for. However, some compilers (including gcc) will always inline at least some methods, whether you want them to or not. If you're willing to modify your code, you can probably force it to generate out-of-line instantiations, maybe something like this:

template<int N> struct fact { 
  enum { value = N * fact<N-1>::value }; 
  int *dummy() { return &fact<N-1>::value; }
};
abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Thanks! Modifying code is not really an option because 99% of instantiated class templates are from Boost.MPL and etc., and I want to have a clean count of those as well. – TemplateRex Jul 10 '12 at 06:12
  • I believe MSVC can be set to turn off absolutely all inlining and optimization, which means you will get an out-of-line instantiation for everything, but I don't think any other compiler has such settings. – abarnert Jul 10 '12 at 17:49
2

There is a tool written by Steven Watanabe that can be used to count the number of template instantiations. You can get it here. Basically, it modifies the code so that a compiler warning is generated every time a class is instantiated and you can then process the resulting text with regexes, for instance.

MadScientist
  • 3,390
  • 15
  • 19