Template function parameters
Monday, June 15th, 2009Started pushing patches produced in packaging KDE 4.3-beta2 on OpenSolaris to the KDE SVN repo yesterday. Started on some safe targets, like KPilot, where I know the codebase pretty well. One of my patches was “add a newline at end of file”, which is one of those kind-of-dorky fixes that sometimes needs to happen.
There was one interesting patch, though, which again illustrates how gcc stretches (or violates) the C++ standard for convenience. The issue if templates that take function parameters, like this one:
template <int (*f)(int)> class A { } ;
This is a template you can instantiate with a single function that takes an int, returning int. For instance, close() would fit the bill. Or would it? In C++, functions also have linkage — this could be either C++ linkage (default) or extern “C” linkage. In the example above, f() has C++ linkage. This means that you can’t use close() as a parameter to this template, because close() has C linkage.
With gcc you can. It glosses over this difference, but standard-conforming compilers will refuse to compile this. It’s apparently a confusing and contentious issue, given the number of blog entries (like this one) and forum posts dedicated to it. If it had been just KPilot, I suppose I would have just committed stuff and moved on, but template function parameters show up in Akonadi as well, so I suspect they will get more use as time goes on.
The point is you can’t write
template <extern "C" int (*f)(int)> class A { } ;
to specify the linkage of template parameter f. There are apparently two ways of working around this. One is to use a typedef to introduce the linkage into the function type, like so
extern "C" typedef int (*cfunc)(int);
template <cfunc foo> class A { } ;
The other is to introduce an intermediate function with C++ linkage (as expected by the original template) that calls the intended target function with C linkage, like so:
int _close(int fd) { return close(fd); }
// ..
A<_close> a(0);
Here we introduce an intermediate function _close that just calls the original function; the only difference is the linkage of the two. Making _close static inline should keep the overall impact low (I haven’t investigated).
Which approach you choose depends on how much control you have over the template definition. For templates defined by an external library, only the latter might be possible.