Templates across API boundaries: Powerful but problematic

March 07, 2016

scross-March 07, 2016

C++ is controversial. For every discussion about it, a certain percentage of people will love it and another substantial group will hate it. Above all, one feature highlights this divide: templates. Templates have many problems: they slow compile times, force implementations to be specified in headers and can bloat generated code. However they’re also a powerful mechanism for programming against generic types.

There can be no doubt that templates are a key part of the C++ language; the standard library relies on them heavily and they’ve been adopted throughout libraries such as Boost. This series of articles explains the problems with C++ templates and outlines new and exciting approaches for enhancing their capabilities and eliminating their drawbacks. In this first part, I define templates and discuss problems engineers have faced in dealing with templates across API boundaries. 

What are templates?
Here’s a very simple example: 

template <typename T>
T divide(T a, T b) {
   return a / b;
}

This is a template for a function which works for any type ‘T’, which you can instantiate with ‘T=int’, ‘T=float’ etc. For example:

assert(divide<int>(5, 2) == 2);
assert(divide<float>(5.0f, 2.0f) == 2.5f);
 

Of course, the utility of templates is clearer when you’re building containers, such as resizable arrays, lists, etc, all of which are in the C++ standard library.

The key point to remember is that there is no such function ‘divide’; it’s a template for creating functions. The real functions appear when the compiler performs substitutions; a function is generated for each instantiation.

Templates in APIs
Consider the following:

a.cpp:

template <typename T>
T divide(T a, T b);
void f() {
   int a = divide<int>(b, c);
   // ...
}
 

b.cpp:

template <typename T>
T divide(T a, T b) {
   return a / b;
}

Is this going to work?

We’ve declared the template in a.cpp and implemented it in b.cpp. For a normal function, this would work splendidly.

But it won’t work for templates. Remember, they’re templates of a function, not real functions themselves. The compiler needs to generate the real functions, and to do that it needs to see all the template implementation.

The export keyword
No discussion of this topic would be complete without mentioning the mysterious export keyword.

It turns out that C++ developers have known about these problems for a long time. Hence the ‘export’ keyword was invented in a C++ standard to be a solution to this problem. Unfortunately it turns out to only make things worse and has only ever been implemented by the Edison Design Group.

Next page >>

< Previous
Page 1 of 3
Next >

Loading comments...