目录
模板代码的组织结构与模板的显式实例化和声明
模板代码的组织结构
- 普通类:类定义和类实现要分别放在.h头文件和.cpp源文件中。
- 编译项目时编译器会针对每个.cpp源文件作为一个编译单元来编译
示例
- myclass.h
#ifndef __MYCLASS_H__ #define __MYCLASS_H__ #include <iostream> //类定义 //class MYClass //{ //public: // void func(); //}; //类模板的定义 template <typename T> class MYClass { public: void func(); }; #endif
- myclass.cpp
#include <iostream> #include "myclass.h" using namespace std; 类实现 //void MYClass::func() //{ // std::cout << "MYClass::func成员函数执行了!" << endl; //} template <typename T> void MYClass<T>::func() { std::cout << "MYClass::func成员函数执行了!" << endl; }
- main.cpp
#include <iostream> #include "myclass.h" int main() { /*MYClass mycls; mycls.func();*/ MYClass<int> mycls; mycls.func(); return 0; }
- 编译报链接错误(原因:针对每个.cpp源文件作为一个编译单元来编译,此处myclass.cpp文件没有实例化)
- 类模板(函数模板)的定义和实现通常都放在.h头文件中,而不能把定义和实现代码分开。
- 如果多个.cpp源文件都实例化出来了MYClass<int>类,那么链接时编译器会选择其中一个MYClass<int>,其他的丢弃掉,这叫贪婪实例化。
上面myclass.h应改为,特化版本也写在.h文件中(类模板(函数模板)的定义和实现通常都放在.h头文件中)
#ifndef __MYCLASS_H__ #define __MYCLASS_H__ #include <iostream> //类模板的定义 template <typename T> class MYClass { public: void func(); }; //类模板的实现 template <typename T> void MYClass<T>::func() { std::cout << "MYClass::func成员函数执行了!" << std::endl; } //特化版本的MYClass可以放在这里 template <> class MYClass<int> { public: void func(); }; //template <> //不要加这行 void MYClass<int>::func() { std::cout << "MYClass<int>::func成员函数执行了!" << std::endl; } #endif
模板的显式实例化,模板声明,代码组织结构
- 通过显式 实例化 来避免这种生成多个相同类模板实例的开销。
- ca.h
#ifndef __CA_H__ #define __CA_H__ template <typename T> void myfunc(T v1, T v2) { std::cout << v1 + v2 << std::endl; } //类模板A声明 template <typename C> class A { public: template <typename T2> A(T2 v1, T2 v2); //构造函数模板 template <typename T> void myft(T tmpt) { std::cout << tmpt << std::endl; } public: void myfuncpt() { std::cout << "myfuncpt()执行了" << std::endl; } C m_ic; }; //类模板A实现 template <typename C> template <typename T2> A<C>::A(T2 v1, T2 v2) { std::cout << v1 << v2 << std::endl; } #endif
- test.cpp(显示定义模板)
#include <iostream> #include "ca.h" using namespace std; template class A<float>; //这叫“实例化定义”。一般只有一个.cpp文件里这样写,编译器为其生成代码。 template void myfunc(int& v1, int& v2); //函数模板实例化定义,编译器会为其生成实例化代码 void mfunc() { A<float> a(1, 2); a.myft(3); //3 }
- main.cpp
#include <iostream> #include "ca.h" extern template class A<float>; //模板实例化声明,其他.cpp源文件都这样写,本行一般写在.cpp源文件的上面位置 extern template void myfunc(int& v1, int& v2); //函数模板实例化声明 int main() { A<int> d(6, 7); //int版本的A(A<int>)会被实例化出来。 A<float> a(1, 2); A<float> a2(1.1, 2.2); a.myft(3); //3 return 0; }
- vs2017,vs2019如果使用模板显示实例化,则会将类中的普通成员函数全部实例化出来,不论后面是否会用到。
- 所以使用vs2017,vs2019,不推荐使用类模板显式实例化特色。对于其他平台,有条件的自己测试。了解这种方式只是为了看懂这类代码。