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;
    }
}

生成文件:
run: prod test
    ./prod
    ./test

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

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

clean:
    -rm *.o prod test

使用GCC 4.3.2(以及“用于AIX的IBM XL C / C++,V11.1(5724-X13)”),我得到的结果是我期望的:
$ 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

也就是说,我通过将其与提供了比库提供的功能模板更专业的功能的对象链接来将新功能注入(inject)客户端。

但是,如果我使用“CC:Sun C++ 5.12 SunOS_sparc修补程序148506-14 2013/09/24”,则会收到此错误:
$ 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

我的解决方案必须与所有这三个编译器一起使用。我只是因为在GCC和AIX中有一些未定义的行为而感到幸运吗?我可以传递一些选项给Sun编译器以使其正常工作吗?我想做的事情是否表明我没有完全理解这些模板概念?请赐教!

最佳答案

您将testlibmock.o链接在一起的client.o二进制文件违反了一个定义规则(在客户端翻译单元中,它使用默认版本,在libmock翻译单元中,它使用专用版本),因此两种链接器行为都可以。

我将继续考虑替代方案,但现在我唯一能想到的解决方案是根据您是否在进行模拟测试构建,有条件地将libmock.h包含在client.cpp中。

10-08 04:16