一直以为自己对 template 的理解有问题,考虑到 template 是用到时再实例化,所以不能像一般的 class 那样写,比如这样:
// foo.h
class Foo
{
public:
Foo();
Type bar(Type&);
private:
Type _val;
};
// foo.cpp
#include"foo.h"Foo::Foo()
: _val(0)
{};
Type Foo::bar(Type&val)
{
_val = val;
return _val;
}
这就是所谓的“分离编译模式”了,也就是类的定义和成员函数声明在头文件中,成员函数实现在另一个文件中。这样做的好处很多:
- 代码条理清晰,代码多了也碍眼。
- 包括该模块时,可以隐藏具体实现细节。
- 减少调用者包括的头文件
实现中用到的库文件、头文件,可以不被该模块包含者包含,如实现中用到了 assert,可以只在cpp文件中包括cassert文件。
- 优化编译速度
如只有cpp文件改动头文件没有改动时,调用者不用重新编译;而如果是“包含编译模式”(合在一起)的话,调用者也得重新编译了,也不知道写代码(特别是Debug)时,有什么时间都花在了编译上了。
上面的 class 封装成 template 就成了:
// foo.h
template <class>
class Foo
{
public:
Foo();
Type bar(Type&);
private:
Type _val;
};
// foo.cpp
template <class>
Foo <type>
::Foo()
: _val(0)
{};
template <class>
Type Foo <type>
::bar(Type&val)
{
_val = val;
return _val;
}
一些资料上也提到了 template 的“分离编译模式”,大致有以下这几种:
- export 关键字法
- cpp 实现文件包含法
- 只在头文件中声明(伪分离)
1. export 关键字法
也就是实现文件中的函数定义都加上关键字 export,来声明一个可导出的函数模板。
// model2.h
// 分离模式:只提供模板声明
template <typename>
Type min( Type t1, Type t2 );
// model2.c
// 模板定义
export template <typename>
Type min( Type t1, Type t2 ) {/* . . . */}
使用函数模板min()实例的程序只需在使用该实例之前包含这个头文件:
// user.c
#include"model2.h"int i, j;
double d = min( i, j ); // OK: 用法,需要一个实例
可惜对于类是没法用了。。。
2. cpp 实现文件包含法
也就是在头文件的底部包含cpp文件
// foo.h
#ifndef _FOO_H_
#define _FOO_H_
template <class>
class Foo
{
public:
Foo();
Type bar(Type&);
private:
Type _val;
};
#include"foo.cpp"#endif // _FOO_H_
3. 只在头文件中声明(伪分离)
这个就比较无语了。。。
// foo.h
#ifndef _FOO_H_
#define _FOO_H_
#include"foo.cpp"#endif // _FOO_H_
// foo.cpp
template <class>
class Foo
{
public:
Foo();
Type bar(Type&);
private:
Type _val;
};
template <class>
Foo <type>
::Foo()
: _val(0)
{};
template <class>
Type Foo <type>
::bar(Type&val)
{
_val = val;
return _val;
}
总结:
经过试验,VS2008不支持分离编译模式(前两种),只支持“第三种”,可以忽略了。。
纠正:
2009-11-27 查看 OpenCV2.0 源码后纠正上面的总结,并得到VS2008的“分离编译模式”注意点,解决方法有两种:
- 到实现文件的后缀名改成属于头文件的后缀名,如h,hpp等,这样VS就不会编译实现文件了,也就是不生成obj文件。
- 或者,自定义实现文件的编译方式,右击实现文件-》属性中设置,快捷键ALt + F7,选择自定义,也就是默认不编译。
再次总结:
问题的真正原因往往会被表象所迷惑。
参考:
C++ Template学习笔记之函数模板(5)——模板编译模式 1.
请问在vs2005中类模板的编译采用的是哪种编译模型? 1.
C++ Template: Why do I get unresolved externals with my template code? 1.