14

I use Visual Studio 2012 and he have cases where we added templates parameters to a class "just" in order to introduce a "seam point" so that in unit-test we can replace those parts with mock objects.

How do you usually introduce seam points in C++: using interfaces and/or mixing based on some criteria with implicit interfaces by using templates parameters also ? One reason to ask this is also because when compiling sometimes a single C++ file (that includes templates files, that could also include other templates) results in an object file being generated that takes in the order of around 5-10 seconds on a developer machine.

VS compiler is also not particularly fast on compiling templates as far as I understand, and because of the templates inclusion model (you practically include the definition of the template in every file that uses it indirectly and possibly re-instantiate that template every time you modify something that has nothing to do with that template) you could have problems with compile times (when doing incremental compiling).

What are your ways of handling incremental(and not only) compile time when working with templates (besides a better/faster compiler :-)).

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
Ghita
  • 297
  • 1
  • 2
  • 10
  • This sounds way complicated. Are you sure there isn't a simpler way to do this by employing some simple loose-coupling with interfaces and some Dependency Injection? – Robert Harvey Nov 28 '12 at 18:13
  • 1
    @RobertHarvey dependency injection is made using template parameters. In production code where I instantiate these I have slow compile times. – Ghita Nov 28 '12 at 19:18
  • 5
    Are you using C++11? see http://en.wikipedia.org/wiki/C%2B%2B11#Extern_template – mike30 Nov 28 '12 at 19:35
  • @mike that could be helpful. Just found out that a way to quite dramatically speed things up is to include for example all std headers in stdafx.h, *even* if you include the same headers also in every *.h file as required for "compile in isolation" – Ghita Nov 28 '12 at 20:11
  • 3
    Since Andrei Alexandrescu has writte "Modern C++ design", lots of C++ programmer think they must use templates for all and everything and let the compiler handle as much as possible. That typically leads to those effects you are describing. Formerly (and currently still for programmers using other languages), it was absolutely ok not to use templates and handle things like dependency injection with run time mechanics, even when this needs some CPU cycles more for the end user (which he will almost never notice). Honestly, I am sure Robert is 100% correct and thats the way you think about it. – Doc Brown Nov 28 '12 at 20:47
  • @DocBrown I am also evaluating now the effects of using extern templates to control the point of instantiation, but as I've said controlling included headers using stdafx helps a lot also – Ghita Nov 28 '12 at 21:37
  • 1
    @Ghita: IMHO using template meta programming is often just a form of premature optimization (and sometimes just overkill) - as far as you don't write libs like the STL with comparable requirements. You trade-off some performance-gain for bigger compile times, less maintainability and lots of hard-to-understand error messages. Using "extern templates" may help you now on the short-term, but if I were in your shoes, I would also think about long-term improvements. – Doc Brown Nov 29 '12 at 12:07
  • 1
    @DocBrown You are probably right. The main thing we decided to consider for our project now is thsi: don't consider using templates just for the sake of introducing seam points in TDD. Of course if genericity is required for some piece of library code we use templates as it's the only way to achieve that. Also maybe in performance critical pieces of code where virtual interfaces do not make a lot of sense – Ghita Nov 29 '12 at 18:33
  • 5
    @DocBrown. Conversely, you could say *avoiding* templates to improve build performance is a premature optimization. Templates are the ideal abstractions for many problems. – mike30 Nov 29 '12 at 20:57
  • @mike Yeah :-). Actually for our case, by just using precompiled header (and including there all std headers) we had for a project reduced the compilation from 1 min 30 seconds to around 30 seconds. – Ghita Dec 01 '12 at 17:54
  • @DocBrown: I call that premature generalization. It does just as much damage as premature optimization. – kevin cline Jan 13 '13 at 03:36

3 Answers3

11

If your templates parameters can only assume a finite (and small) set of values, you could move their definition in a source file, and use explicit instantiation.

For instance, in aaa.h you only declare the template functions f and g:

template <int n>
int f();

template <class T>
void g(int a);

Assume n template parameter can only be 1, 3, 6, and T template parameter can only be int, long and void *.

Then you define them in aaa.cpp like this:

template <int n>
int f()
{
    ...
}

template <class T>
void g(int a)
{
    ...
}

template int f<1>();
template int f<3>();
template int f<6>();

template void g<int>(int a);
template void g<long>(int a);
template void g<void *>(int a);

In this way the compiler instantiates the template for the given parameters when compiling aaa.cpp. When compiling client code, it assumes that the definitions exist somewhere, and the linker will take care of that.

#include "aaa.h"

int main()
{
    f<1>();
    f<3>();
    f<6>();

    g<int>(5);
    g<long>(5);
    g<void *>(5);
}

You can explicitly instantiate template classes too. The drawback is that you can not use f or g with other template parameters.

#include "aaa.h"

int main()
{
    f<5>();
}

results in

undefined reference to `int f<5>()'

I used this technique in a project where few complex classes depended on a small (< 10) set of integer template parameters, and it significantly reduced compilation time (since the compiler did not have to parse the complex template definitions when compiling the client code). Of course you may get lesser improvements, depending on the actual code.

Claudio
  • 226
  • 2
  • 4
2

Once I used a strange solution for a similar problem: Including the STL lead to compile times like several seconds per source file - no matter how tiny it was. So I included all my source files into one master file and the compilation time per file hardly changed... which meant a speed up of factor 20+ as I had only a single file to compile.

In order to keep the design clean I continued to maintain a makefile, but never actually used it (except for verifying it still works).

maaartinus
  • 2,633
  • 1
  • 21
  • 29
0

We used to fire off a big task to build our precompiled headers and precompiled templates overnight, and just build against those the following day.

Ti Strga
  • 119
  • 2