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(以及“IBM XL C / C ++ for AIX,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
也就是说,我通过将新功能链接到一个对象来为客户端注入新功能,该对象提供了比库提供的更专业的功能模板。
但是,如果我使用“CC:Sun C ++ 5.12 SunOS_sparc Patch 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编译器以使其工作吗?我想要做的是否表明我不完全理解这些模板概念?请赐教!
答案 0 :(得分:2)
将test
和libmock.o
链接在一起的client.o
二进制文件违反了一个定义规则(在客户端翻译单元中,它使用默认版本,而在libmock翻译单元中,它使用专用的版本)因此两个链接器行为都可以。
我会继续考虑替代方案,但现在我能想到的唯一解决方案是根据您是否正在进行模拟测试构建,在libmock.h
中有条件地包含client.cpp
。