模版的分离编译 解决方案

这篇具有很好参考价值的文章主要介绍了模版的分离编译 解决方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

回顾

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

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

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

原因分析

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

实际上,报的是链接错误

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也是采用的这样的办法。文章来源地址https://www.toymoban.com/news/detail-464843.html

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;
}

到了这里,关于模版的分离编译 解决方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • webase编译合约一直转圈卡住解决方案

    进入webase-web目录,然后进入staticjs目录,执行以下命令:

    2024年02月05日
    浏览(33)
  • 前后端分离项目跨域问题No ‘Access-Control-Allow-Origin‘解决方案

    一.问题背景 前后端分离项目跨域问题,浏览器控制台报错: No \\\'Access-Control-Allow-Origin\\\' header is present on the requested resource. 请求方法为OPTIONS,状态值为302或403。 本文解决常见的CORS跨域问题,以及,集成CAS 5.3单点登录内嵌页面时,发送复杂请求产生的跨域问题。 二.解决方案

    2024年02月02日
    浏览(45)
  • 免费背景音人声分离解决方案MVSEP-MDX23,足以和Spleeter分庭抗礼

    在音视频领域,把已经发布的混音歌曲或者音频文件逆向分离一直是世界性的课题。音波混合的物理特性导致在没有原始工程文件的情况下,将其还原和分离是一件很有难度的事情。 言及背景音人声分离技术,就不能不提Spleeter,它是一种用于音频源分离(音乐分离)的开源

    2024年02月04日
    浏览(27)
  • SSL连接错误导致的编译错误——详细解决方案

    SSL连接错误导致的编译错误——详细解决方案 在处理大数据时,我们经常会遇到与SSL(Secure Sockets Layer)连接相关的问题。其中之一是\\\"SSL peer shut down incorrectly\\\"错误,这个错误提示表明SSL连接的对等方(peer)未正确关闭连接,导致编译错误。本文将介绍如何解决这个问题,并

    2024年02月03日
    浏览(33)
  • Vivado 工程长时间编译的原因分析与解决方案

    Vivado 工程长时间编译的原因分析与解决方案 在进行 FPGA 开发过程中,Vivado 是一款常用的综合工具,但是随着项目的复杂度和规模增大,编译时间也会变得越来越长。本文将对 Vivado 工程编译时间过长的原因进行总结,并提供相应的解决方案,旨在帮助工程师提高 FPGA 开发的

    2024年02月03日
    浏览(30)
  • uniapp中微信小程序不能编译style绑定方法的解决方案

    这是我的代码设置了根据传参显示不同字体颜色和不同背景色 这两个方法我都写在methods中 在浏览器中H5和app模拟器的效果是一样的如图 在HbuildX中运行至微信开发者工具无效,并且报错如图 第一步 第二步 在computed添加如下代码 至此修改成功,微信开发者工具运行效果如图所

    2024年02月16日
    浏览(35)
  • MAC(M1芯片)编译Java项目慢且发热严重问题解决方案

    使用idea编译项目等操作,经常性发热严重,并且时间慢。直到昨天编译一个项目用时30分钟,电脑温度很高,并且有烧灼的味道,于是有了此篇文章。 1、针对于编译慢的问题,首先想到就是内存不够,于是就通过活动监视器查看cpu使用情况;具体情况如下图所示(不是排查

    2024年04月12日
    浏览(31)
  • CMAKE编译 opencv、opencv_contrib出现ADE无法下载解决方案

    问题: CMake Error at xxxx/DownlodeADE.cmake:23(add_library): 解决方案:你的opencv的安装路径下,(我的路径就是opencv4.5.4/modules/gapi/cmke/ )找到如下图片,打开DownloadADE.cmake文件 文件中有github网址,需要去文件中提供的网址下载文件,我的opencv版本是4.5.4,有需要可以滴滴。 第一行是你

    2024年02月22日
    浏览(46)
  • vs2017实现linux远程编译报错“CMake 缺少以下功能:serverMode“解决方案

    背景 window系统vs2017使用cmake实现linux远程调试和编译时,搭建的环境报 CMake 缺少以下功能:“serverMode”。请参阅 https://aka.ms/linuxcmakeconfig 了解详细信息 错误,如何解决? 经排查,发现远程开发环境的cmake版本不支持serverMode模式,因此,无法实现远程编译 解决方案 验证远程目

    2024年02月11日
    浏览(32)
  • 【linux】记录archlinux软件包更新后lualatex无法编译的一种解决方案

    操作系统:archlinux Kernel: 6.4.11-arch2-1 包管理器:pacman 日期:2023.08.25 今天一如往常地进行软件包更新: 随后,在使用luelatex对我的论文(latex)进行编译时,无法编译。想到在软件更新前还能编译,更新后就无法编译,必然是软件包版本问题。在命令行运行lualatex报错: 所以

    2024年02月11日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包