1

lib.h:

#include <iostream>
namespace lib {
    template <class T>
    void f(T t)
    {
        std::cout << "lib f " << t << std::endl;
    }
}

client.cpp:

#include "lib.h"

// explicit instantiation
template
void lib::f(char);

int main()
{
    lib::f('x');
}

libmock.h:

#include <iostream>
#include "lib.h"
namespace lib {
    template <>
    void f(char c)
    {
        std::cout << "libmock f " << c << std::endl;
    }
}

Makefile:

run: prod test
    ./prod
    ./test

prod: client.o
    ${CXX} -o $@ $^

test: client.o libmock.o
    ${CXX} -o $@ $^

clean:
    -rm *.o prod test

Using GCC 4.3.2 (and also "IBM XL C/C++ for AIX, V11.1 (5724-X13)"), I get the results that I expect:

$ make
g++    -c -o client.o client.cpp
g++ -o prod client.o
g++    -c -o libmock.o libmock.cpp
g++ -o test client.o libmock.o
./prod
lib f x
./test
libmock f x

That is, I've injected new functionality into the client by linking it with an object that provides a more-specialized function template than the one offered by the library.

However, if I use "CC: Sun C++ 5.12 SunOS_sparc Patch 148506-14 2013/09/24", then I get this error:

$ CXX=CC make
CC    -c -o client.o client.cpp
CC -o prod client.o
CC    -c -o libmock.o libmock.cpp
CC -o test client.o libmock.o
ld: fatal: symbol 'void lib::f<char>(__type_0)' is multiply-defined:
        (file client.o type=FUNC; file libmock.o type=FUNC);
Makefile:9: recipe for target 'test' failed
make: *** [test] Error 2

My solution must work with all three of these compilers. Am I just getting lucky with some undefined behavior in GCC and AIX? Are there some options I could pass to the Sun compiler to get this to work? Does what I'm trying to do show that I'm not fully understanding these template concepts? Enlighten me, please!

bogdan
  • 9,229
  • 2
  • 33
  • 48
feuGene
  • 3,931
  • 2
  • 33
  • 46

1 Answers1

2

Your test binary that links libmock.o and client.o together violates the one definition rule (in the client translation unit it uses the default version and in the libmock translation unit it uses the specialized version) and thus both linker behaviors are ok.

I will continue thinking about alternatives but right now the only solutiion I can think of is to conditionally include libmock.h in client.cpp based on whether you're doing the mock test build or not.

Mark B
  • 95,107
  • 10
  • 109
  • 188