hgiesel
hgiesel

Reputation: 5648

Using templates in Libraries

Setup

a.h

void foo(void);

a.cc

#include "a.h"
void foo(void) { /* do something */ }

These both are compiled to a shared library called libA

b.h

#include "a.h"

void bar(void);
template <typename T>
void baz(void)
{
    foo();
}

b.cc

#include "b.h"

void bar(void)
{
    foo();
}

These two get compiled to the shared library libB, and are linked against libA.

Now I write my main program, which is linked against libB, but not libA.

main.cc

#include "b.h"

int main(void)
{
    bar();  // Okay, compiles
    baz<int>();  // Undefined symbol *foo()*, referenced from void bar<int>() in main-(...)
}

Explanation

I kinda get, why this throws up an error. In libB I have a template declaration, which can be used to instantiate functions, although it doesn't instantiate any in libB itself.

In main.cc however it instantiates the function void bar<int>(void), which is then placed in the object code for main.cc, where it can't find libAs foo() function and throws the linking error.

And who would have thought? If I link main.cc against libB as well, it works just fine.

My question is however: How can I work with templates efficiently, without without having to link against the original library and/or having to instantiate every single version of bar<>(), that I intend to use?


EDIT - clarification from chat

The goal is to allow libB to provide templates, without requiring explicit instantiation in libB, and without the client being coupled to libB's implementation details.

Upvotes: 0

Views: 116

Answers (1)

Useless
Useless

Reputation: 67713

Template definitions are part of the public interface of your library (libB, in this case).

The only way to decouple a client of libB from its implementation details (in this case: the dependency on libA), is the usual: don't make them public. Hide them inside libB. If they're visible in b.h, they're part of the public interface.

The simple solution in this case is to provide a (non-template, non-inline) function in libB which abstracts the dependency on libA:


// b.h
void do_fooish_things();

template <typename T>
void baz(void)
{
    do_fooish_things();
}

// b.cc
#include <libA/a.h>
void do_fooish_things() {
    // hidden implementation detail
    libA::foo();
}

Upvotes: 1

Related Questions