回顾

对于模版,在之前我们就已经讲过,模版不支持分离编译(即声明定义不在同一文件中)。

类中,我们知道,对于代码量比较小的函数,会默认识别成内联函数,增加代码运行的效率,而一些代码量比较大的函数,则仍然进行函数调用。

但是有些函数实在长,如果这些函数全写在类里面,十分不利于我们对代码的可读性,所以大佬就有这么两个办法来完善这些问题。

原因分析

首先我们要明白为什么模版对于声明定义分离会报错?

实际上,报的是链接错误

ps:这里我们已经声明定义分离了

test.obj : error LNK2019: 无法解析的外部符号 "public: void __cdecl fjz::vector<int>::push_back(int const &)" (?push_back@?$vector@H@fjz@@QEAAXAEBH@Z),函数 main 中引用了该符号

这种报错一般是编译器没有找到对应的函数定义。

可是为什么?

这是因为在类外定义的函数无法实例化!!

模版类(函数)你可以理解为只是一个 模具 ,这个模具要根据你的模版参数T...进行实例化,而类外定义的函数因为不在类里面,没有办法跟着类的实例化一起实例化!

解决方案一

以vector举例

vector.h

template<class T>
class vector
{
public:typedef T* iterator;typedef const T* const_iterator;void reserve(size_t n);void push_back(const T& val);iterator erase(iterator pos);iterator erase(iterator first, iterator last);public:iterator _start;iterator _finish;iterator _end_of_storage;
};

这里我省略掉了很多不需要声明定义分离的短函数。

vetcor.cpp

#include"vector.h"
template<class T>
void vector<T>::reserve(size_t n)
{if (capacity() < n)   //判断是否需要扩容{size_t sz = size();   //保存size的数据T* tmp = new T[n];if (_start)           //如果_start不为空指针,则进行拷贝和delete{for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];   //调用赋值来完成深拷贝}delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}
}template<class T>
void vector<T>::push_back(const T& val)
{if (_finish == _end_of_storage){reserve(empty() ? 4 : capacity() * 2);  //如果数据为空,则给初始空间为4}*_finish = val;_finish++;
}template<class T>
typename vector<T>::iterator vector<T>::erase(typename vector<T>::iterator pos)
{assert(pos < _finish);for (int i = 0; i < _finish - pos - 1; i++){pos[i] = pos[i + 1];}--_finish;return pos;
}template<class T>
typename vector<T>::iterator vector<T>::erase(typename vector<T>::iterator first,typename vector<T>::iterator last)
{assert(last <= _finish);assert(first <= _finish);size_t len = last - first;for (int i = 0; i < _finish - last; i++){first[i] = last[i];}_finish -= len;return first;
}

仔细看分离定义的格式,对于iterator 这是我们在类中重定义的类型,必须要声明他是一个在vector中的类型,否则无法编译!

目前这样就已经是声明定义分离的标准格式了,如果我们现在进行vector相关的函数调用,就会出现我们刚刚上面的说的链接问题, .cpp中定义的函数无法实例化

那么解决办法是什么?

让它实例化!

#include"vector.h"
template<class T>
void vector<T>::reserve(size_t n)
{if (capacity() < n)   //判断是否需要扩容{size_t sz = size();   //保存size的数据T* tmp = new T[n];if (_start)           //如果_start不为空指针,则进行拷贝和delete{for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];   //调用赋值来完成深拷贝}delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}
}template<class T>
void vector<T>::push_back(const T& val)
{if (_finish == _end_of_storage){reserve(empty() ? 4 : capacity() * 2);  //如果数据为空,则给初始空间为4}*_finish = val;_finish++;
}template<class T>
typename vector<T>::iterator vector<T>::erase(typename vector<T>::iterator pos)
{assert(pos < _finish);for (int i = 0; i < _finish - pos - 1; i++){pos[i] = pos[i + 1];}--_finish;return pos;
}template<class T>
typename vector<T>::iterator vector<T>::erase(typename vector<T>::iterator first,typename vector<T>::iterator last)
{assert(last <= _finish);assert(first <= _finish);size_t len = last - first;for (int i = 0; i < _finish - last; i++){first[i] = last[i];}_finish -= len;return first;
}template
vector<int>;   //实例化vector<int>template
vector<double>;   //实例化vector<double>

这样就能实例化了,可是这种办法缺陷也很明显,你需要在.cpp文件中提前加入需要实例化的类型,没有加入的则仍然会编译错误,所以这种办法我们很少用,干脆不如就不要不同文件分离编译。

而下面介绍的方案二这种办法也是比较推崇的方法

解决方案二

在同一文件进行声明定义分离,这也是最好的办法,STL也是采用的这样的办法。

template<class T>
class vector
{
public:typedef T* iterator;typedef const T* const_iterator;void reserve(size_t n);void push_back(const T& val);iterator erase(iterator pos);iterator erase(iterator first, iterator last);public:iterator _start;iterator _finish;iterator _end_of_storage;
};template<class T>
void vector<T>::reserve(size_t n)
{if (capacity() < n)   //判断是否需要扩容{size_t sz = size();   //保存size的数据T* tmp = new T[n];if (_start)           //如果_start不为空指针,则进行拷贝和delete{for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];   //调用赋值来完成深拷贝}delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}
}template<class T>
void vector<T>::push_back(const T& val)
{if (_finish == _end_of_storage){reserve(empty() ? 4 : capacity() * 2);  //如果数据为空,则给初始空间为4}*_finish = val;_finish++;
}template<class T>
typename vector<T>::iterator vector<T>::erase(typename vector<T>::iterator pos)
{assert(pos < _finish);for (int i = 0; i < _finish - pos - 1; i++){pos[i] = pos[i + 1];}--_finish;return pos;
}template<class T>
typename vector<T>::iterator vector<T>::erase(typename vector<T>::iterator first, typename vector<T>::iterator last)
{assert(last <= _finish);assert(first <= _finish);size_t len = last - first;for (int i = 0; i < _finish - last; i++){first[i] = last[i];}_finish -= len;return first;
}

模版的分离编译 解决方案相关推荐

  1. 如何解决类模板的分离编译问题?

    一模板: 模板不是数据类型,只能算是一种行为集合的表示.编译器在使用模板时,通过更换模板参数来创建数据类型.这个过程就是模板实例化(Instantiation), 从模板类创建得到的类型称之为特例(s ...

  2. C++ 泛型编程(二):非类型模板参数,模板特化,模板的分离编译

    目录 非类型模板参数 函数模板的特化 类模板的特化 全特化 偏特化 部分参数特化 参数修饰特化 模板分离编译 问题分析 解决方法 非类型模板参数 模板的参数分为两种,一种是非类型参数,一种是类型参数. ...

  3. C++模板——模板特化、分离编译

    这里写目录标题 一.泛型编程与模板 二.函数模板 1.概念 2.原理 3.函数模板的实例化 3. 模板实现复数类的加法 4.模板参数的匹配原则 三.类模板 1.定义格式 用类模板实现顺序表 2.非类型 ...

  4. c++模板函数声明定义分离编译错误详解

    今天看到accelerated c++上有个简单的vector容器的实现Vec,就再vs2008上编译了下: /  Vec.h #ifndef GUARD_VEC_H #define GUARD_VE ...

  5. Eclipse不编译解决方案

    Eclipse不编译解决方案 参考文章: (1)Eclipse不编译解决方案 (2)https://www.cnblogs.com/yzw23333/p/7560045.html 备忘一下.

  6. PaddleOCR——Visual Studio 2019 环境下C++推理部署 CMake 编译解决方案

    PaddleOCR--Visual Studio 2019 环境下C++推理部署 CMake 编译解决方案 官方文档 环境配置 Step1: 下载PaddlePaddle C++ 预测库 paddle ...

  7. C++ 函数模板与分离编译模式

    代码编译运行环境:VS2017+Debug+Win32 1.分离编译模式 一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件连接起来形成单一的可执行文件的过程 ...

  8. R+markdown+LaTeX 中文编译解决方案

    R+markdown+LaTeX 中文编译解决方案 参考文章: (1)R+markdown+LaTeX 中文编译解决方案 (2)https://www.cnblogs.com/loca/p/45416 ...

  9. 使用Cmake生成跨平台项目编译解决方案

    项目最近有需求在windows下面运行,我花了几周时间将linux的服务器移植到windows下面,目前已经能够正常运行服务器,目前又有了新需求,两边的代码结构和组织是分开的,因此为了两边能够同步维护 ...

最新文章

  1. mvvm command的使用案例
  2. CMU贺斌教授团队提出FAST-IRES技术,利用高密度EEG产生脑信号源的动态图像
  3. A folder failed to be moved——Android SDK的安装问题解决方案
  4. 四十四、Python中的statsmodels模块
  5. wxWidgets:工具栏概述
  6. [号外] Blazor wasm 其实也挺快!
  7. 想通过好的商业模式赚钱,应该钻研“道”还是“术”呢?
  8. Revit Family API 添加几何实体
  9. 第三天.SQL语言基础
  10. 全新版本的SoundSource for Mac - 优质的音频控制软件
  11. VS2010+OpenCV2.4.6永久性配置方法
  12. hough变换检测圆周_Hough变换检测圆(附:MATLAB程序)
  13. UI设计中有哪些常见的风格?
  14. java ready()_Java BufferedReader ready()用法及代码示例
  15. 小伙伴们,线程生命周期、线程池生命周期别再傻傻分不清楚了!!!
  16. APP 跳转微信小程序和回调
  17. 显示器支架什么品牌好?
  18. 【Python量化交易笔记】股票数据获取 (一)
  19. 工作中常用的oracle数据库sql
  20. Linux 安装 Consul并设置开机启动

热门文章

  1. 穆熙妍在节目中秀美鞋
  2. 基因组差异、基因表达差异、基因选择性表达名词辨析
  3. 爱签区块链电子签名助力知产保护数字化
  4. 多品牌“精密空调”能集中监控?Pmcenter来为你解答
  5. 高德地图 错误码说明 对照表
  6. Excel公式教程 数组公式基础:数组扩展
  7. Python进阶-----面向对象2.0(特有属性和方法与私有属性和方法)
  8. 清华大学计算机应用复试题目,2017年清华大学自动化系复试及试题回忆
  9. Python:利用xlwings库实现excel进行插入、删除行操作实例
  10. python实现微信、QQ聊天自动回复【纯物理】