1

lib.h:

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

客户端.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 编译器以使其工作吗?我正在尝试做的事情是否表明我没有完全理解这些模板概念?请赐教!

4

1 回答 1

2

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

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

于 2015-12-09T15:52:02.120 回答