C++ tricks, #6: Explicit template instantiation

This post is very old. Please bear in mind that information here might be incorrect or obsolete, and links can be broken. If something seems wrong, please feel free to comment or contact me and I'll update the post.

Today we take a look at explicit template instantiations (yet another post which is a direct result of user feedback :) ). With explicit template instantiations, you can define a template and instantiate it in a DLL, so clients don’t even have to see the implementation of the template. All you need is a language extension (extern template) which will become part of C++0x, and is currently supported by GCC, Intel and MSVC.

The DLL

Let’s assume we have this great class:

template <typename T>
class Container
{
    public:
    Container (int size);

    ~Container ();

    T		Get (int index) const;

    void	Set (int index, T value);

private:
    T*		data_;
};

and we want to provide our clients an instance which works with integers only. For this to work, we put the definition into a separate file (you’ll see later why), container_impl.h:

template <typename T>
Container<T>::Container (int size)
{
    data_ = new T [size];
}

template <typename T>
Container<T>::~Container ()
{
    delete [] data_;
}

template <typename T>
T		Container<T>::Get (int index) const
{
    return data_ [index];
}

template <typename T>
void	Container<T>::Set (int index, T value)
{
    data_ [index] = value;
}

Then we include both in a file in our DLL, let’s call it container_in.cpp like this:

#include "container.h"
#include "container_impl.h"

template class __declspec(dllexport) Container<int>;

Now clients can already use the integer container, by including only container.h which does not contain the definitions!

More flexibility

But what if clients want to use a float container? With the current solution, they’ll get an error that the definition is not available. To get it working, the client has to include container_impl.h as well. But now, Container<int> will be instantiated twice, which leads to an error. The workaround is to define the instantiation as extern template, which means don’t generate code for this template even if the definition is available (for some reason or another, I just tried and it also works without the extern with Visual C++ 9). The finished file is:

#ifdef DLL_EXPORT  // Set to true when you build the dll
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif

template <typename T>
class Container
{
    // Container declaration
};

#ifndef IN_  // Note: For VC++, you can leave out the extern
extern template class API Container<int>;
#endif

The container_in.cpp file has to #define IN_ now. The client works like this:

#include "../shared_lib/templ.h"
#include "../shared_lib/templ.hpp"

#include <iostream>

int main (int, char**)
{
    Container<float> c1 (5);  // Will be instantiated here

    c1.Set (3, 13.37f);
    std::cout << c1.Get (3) << std::endl;

    Container<int> c2 (4);  // Will be linked in from the DLL

    c2.Set (1, 4711);
    std::cout << c2.Get (1) << std::endl;
}

That’s it!

Related posts:

  1. Pimpl your C++ code
  2. C++ tricks, #1: Compile time checks
  3. Type traits

This entry was posted in Programming and tagged . Bookmark the permalink.

5 Responses to C++ tricks, #6: Explicit template instantiation

  1. Peter L says:

    Anteru -
    Thanks for the very concise C++ tricks # example!
    I just got your explicit templated class instantiation in a DLL code up and running via g++ (gcc) 3.4.5 (mingw-vista special r3) running XP SP2.

    It works great for explicitly instantiating templated classes,
    Originally I was attempting to explicitly instantiate a templated FUNCTION, as opposed to a class… I attempted to do likewise with a templatised Function def, but I guess the required syntax is a bit over my head.. is this capability supported also for function instantiation in a DLL, or perhaps one need to convert it to a static class method??

  2. Anteru says:

    I’m not sure it’s going to work for functions, but my gut feeling is that it should. Syntax should be the same, just leave out the class and add () ;) If you get it working, don’t hesitate to comment; I’d also like to see where this could be useful :)

  3. Peter L says:

    Ive tried explicit templated function instantiation, doesn’t seem to work.
    Thats Ok….I’ve moved on it was easy enough to make the function into a class, and in the longer my code need that to happen any way..

    While your example got me far enough along to mange to figure out what really needed to happen to make things work under both MinGW g++ as well a MS_VC++ 10 Beta 2….

    I ran into a fair amount still needing to be addressed if one is to support both “C” functions as well as “C++” classes inthe same DLL…
    With some messing around, I’ve got a clean fully functional version of your example code, that compiles without adjustment under both tool chains…. send me an EMail so I know how to send you a zip file containing the updated example.

    Currently I seem to be faced with a DLL nameSpace g++, VC++ linking chalange. I have two DLLs Thing_ref.dll and Thing_underTest.dll,
    they both have the same header file, as there inerfaces are the same…… I’m wanting to include both in a cross validation suit.

    namespace ref { #include “Thing.hpp” }
    namespace test { #include “Thing.hpp” }

    That part should work just fine, one should be able to then invoke each in via there corresponding name space prefixes ref:: and test::..

    the problem come at link time, I have looked for but have not yet found any linker options that would allow the symbols of a given DLL
    one is linking with to be enclosed within a link time specified nameSpace during the DLL’s loading process..

    I realize I may be asking for o much here, but how else can one side by side test two DLLs with identical interfaces against each other??

    Any ideas ??

    all the best
    -Peter

  4. Anteru says:

    I’d simply compile your test twice, once again DLL1, then again DLL2, and make sure the behaviour is the same. This should be very easy to maintain, and your approach with trying to link in twice the same will be likely a very fragile solution anyway.

    However, I’m not sure why you need two tests anyway, as your explicit instantiation uses the same code as the template generated path, so you could just as well verify that one version works (instantiated or not), and the other should be fine as well.

    Adding a namespace during linking is not possible (as far as I know.)

  5. Pingback: Code Bloat Hunting | EntBlog

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>