【C++】泛型编程——模板进阶

news2025/1/14 9:37:28

文章目录

    • 前言
    • 1. 模板参数的分类
    • 2. 非类型模板参数
      • 2.1 非类型模板参数的概念
      • 2.2 铺垫
      • 2.2 非类型模板参数的使用
      • 2.4 注意
      • 2.5 array的了解
    • 3. 模板的特化
      • 3.1 概念
      • 3.2 函数模板特化
      • 3.3 类模板特化
        • 3.3.1 全特化
        • 3.3.2 偏特化
          • 部分特化
          • 参数更进一步的限制
    • 4. 模板分离编译
      • 4.1 什么是分离编译
      • 4.2 模板的分离编译
      • 4.3 解决方法
    • 5. 模板总结
      • 5.1 优点
      • 5.2 缺点

前言

在之前的文章里,我们进行了模板初阶的学习( 【C++】泛型编程——模板初阶),了解了什么是泛型编程,学习了函数模板和类模板。
那这篇文章,我们继续学习模板进阶的内容的学习。

1. 模板参数的分类

首先我们来回顾一下:

我们在模板初阶的学习中,定义模板参数是怎么定义的?
是不是使用class或者typename关键字啊,
template<class T1, class T2,...,class Tn>
在这里插入图片描述
对于函数模板来说,我们调用函数时,传的参数是什么类型,T就会被替换成对应的类型,然后实例化出对应的模板函数,我们实际调用的就是函数模板根据具体传入的实参类型实例化出来的模板函数。
在这里插入图片描述

那对于跟在class或者typename之后的这种模板参数,我们把它叫做类型模板参数

即它定义的是一个类型,对应的模板实例化的时候该参数会被替换成一个具体的类型,供其对应的模板类或模板函数使用。

但是呢,这其实只是模板参数的一种:

模板参数分为类型模板参数非类型模板参数

类型模板参数我们已经了解了:

类型形参即:出现在模板参数列表中,跟在class或者typename关键字之后的参数类型名称。

那非类型模板参数又是什么呢?

2. 非类型模板参数

2.1 非类型模板参数的概念

非类型模板参数的概念:

非类型模板参数,就是用一个常量(且必须是整型常量)作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。

什么意思呢?下面我们通过一个栗子细细的给大家介绍一下:

2.2 铺垫

假设我们现在要写一个静态的顺序表,那我们就可以这样搞

在这里插入图片描述
首先这里我们定义了一个标识符(宏)常量N,用N作为当前静态数组的大小,就使得我们后续想要改变数组大小的时候很方便。
其次,我们把它实现成了一个类模板,该类模板有一个模板参数T,那通过上面的了解我们知道这里的T其实就是一个类型模板参数,它定义的是一个类型,这样我们在使用该类模板的时候,指定什么类型,实例化出来的数组(模板类)就存放什么类型的数据。
在这里插入图片描述
这样看起来好像也挺方便的。

但是对于有些情况却不能很好的处理:

如果我们现在想达到这样一种效果,我们想让a1的大小为10 ,而a2的大小为20,目前的实现可以做到吗?
不行啊,虽然这里我们用来#define定义的宏,改变数组的大小是很方便的,但是,这里我们实例化出两个对象,一个大小为10,一个20,是不是做不到啊。

那大家来思考一下:

首先对于类型模板参数来说,他解决了类型的问题。
我们没有学模板之前,写一个数据结构,比如有一个栈,我们一般会有一个typedef,这样想要改变栈里存储的数据的类型很方便,但是如果我们在main函数里定义了2个或者多个栈,想让它们分别存储不同类型的数据,能不能做到呢?
如果typedef的话是不能的,但是在模板初阶的学习之后,借助模板,用类型模板参数是不是就可以解决这个问题啊!
在这里插入图片描述在这里插入图片描述
这样在一个main函数中,我们定义两个栈,就可以让他们分别存储不同类型的数据。

2.2 非类型模板参数的使用

那再回到我们上面的问题,其实这里有点类似:

类型模板参数呢?解决了类型的问题。
那这里我们想让a1大小为10,a2大小为20
在这里插入图片描述
与类型无关啊,那这种情况又该如何解决呢?
🆗,那非类型模板参数的引入,其实就很好的解决了这种问题

类型模板参数定义了一个类型,那非类型模板参数定义的是什么呢?

我们再来回顾一下非类型模板参数的概念:
非类型模板参数,就是用一个常量(且必须是整型常量)作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。
是的,非类型模板参数其实定义的是一个整型常量。
注意:这里的整型不单指int,而是整个整型家族(包括C99引入的bool类型)。

具体怎么用呢?这里我们就可以这样写:

在这里插入图片描述
和类型模板参数一样,直接放在模板参数列表里面就行了。
我们看到这里是这样写的——size_t N,虽然没加const,但是规定它在这里就是常量。
后面我们会验证它是不能修改的。

那这样就可以实现a1的大小是10,a2的大小是20了。

在这里插入图片描述

当然:

非类型模板参数也是可以给缺省值的。
在这里插入图片描述

2.4 注意

再次提醒大家:

非类型模板参数必须是常量且要是整型。

我们可以来验证一下:

这次我们举个函数模板的例子:
首先常量就意味着它不能被修改
在这里插入图片描述
其次必须是整型
在这里插入图片描述
所以说:
浮点数、类对象以及字符串等其它非整形的类型是不允许作为非类型模板参数的。
不过呢,这里提一下,就是C++20允许使用float或double作为非类型模板参数。
在这里插入图片描述
另外要知道:
非类型的模板参数必须在编译期间就能确认结果。

2.5 array的了解

然后我们再来了解一个东西就是:

C++11搞出来了一个新容器——array
其实可以认为就是静态数组,我们看到文档给的解释是固定大小的序列容器
在这里插入图片描述
我们看到array这个类模板其实就用了一个非类型模板参数来作为这个数组的大小。
可以看一下它的成员函数
在这里插入图片描述

🆗,那C++11搞出来这个东西

其实是对标C语言里的静态数组:
我们包一下<array>这个头文件就可以使用它
在这里插入图片描述
那array的底层其实也是一个静态数组,只不过用类进行了封装。

那大家想一下,本来就已经有静态数组了,为什么还要搞出来一个这个,或者说,它于C语言的静态数组相比,有什么进步吗?

嗯~,array可以用迭代器,而数组不能。
是,虽然数组不能用迭代器,但是它也可以用范围for啊,范围for用起来就很方便啊。
那这样看来好像没什么特别之处啊,难道array可以自动初始化?
在这里插入图片描述
并没有。
没啥用啊,与原生的数组相比好像没啥进步啊。
🆗,其实它的优势是对越界的一个检查比数组更严格一点
传统的数组对于越界的检查是一个抽查,有时候越界会报错,而有时候可能就不会
在这里插入图片描述
在这里插入图片描述
越界读,不会报错。
如果越界写:
在这里插入图片描述
在这里插入图片描述
就不一定了,所以我们说是抽查。

那对于array来说:

它对于读写的检查就比较严格,比较全面

在这里插入图片描述

在这里插入图片描述
因为它是一个类嘛,它里面可以拿非类型模板参数这个N去比较,判断你是否越界。
在这里插入图片描述

所以要说它比传统数组的进步的话,可能就这一个点了吧。

所以C++11搞出来这个其实是想让我们以后用数组的时候都用array。
但是大家想一下如果给我们选择的话我们会用这个嘛?
是不是又vector啊,我vector如果越界也能很好的检查啊,并且我vector还能直接初始化,array有哪一点比vector强。

所以,这个设计就感觉有点没必要了😂。
如果要论array和vector的区别的话,那就是array的空间是在栈上开辟的,而vector的空间是在堆上申请的。

所以这个大家了解一下就行,没什么用。

3. 模板的特化

接下来我们再来学一个东西叫做模板的特化。
首先我们来认识一下它的概念。

3.1 概念

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理。

举个栗子:
我们这里现在有一个专门用来进行小于比较的函数模板

template<class T>
bool Less(T left, T right)
{
	return left < right;
}

那我们现在就可以使用它去比较不同类型数据的大小:

int main()
{
	cout << Less(1, 5) << endl; // 可以比较,结果正确
	return 0;
}

我们来看一下结果:

在这里插入图片描述
没有问题,结果正确。

现在我们拿过来一个日期类:

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	bool operator<(const Date& d)const
	{
		return (_year < d._year) ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day);
	}
	bool operator>(const Date& d)const
	{
		return (_year > d._year) ||
			(_year == d._year && _month > d._month) ||
			(_year == d._year && _month == d._month && _day > d._day);
	}
private:
	int _year;
	int _month;
	int _day;
};

他已经重载了大于小于操作符。

那我们现在相比较日期类的大小:

在这里插入图片描述
看一下结果:
在这里插入图片描述
没有问题,结果也是正确的。
但是,这样呢?
在这里插入图片描述
我们再来运行看结果:
在这里插入图片描述
欸,p1指向的日期小于p2指向的日期啊,那结果怎么是0呢?
🆗,因为这里比较的并不是它们指向的日期,而是这两个指针本身,那指针进行比较的话实际比较的是它们存储的地址的大小,所以这里的结果可能并不是我们想要的。
可以看到,Less绝对多数情况下都可以正常比较,但是在特殊场景下就得到错误的结果。
上述示例中,p1指向的d1显然小于p2指向的d2对象,但是Less内部并没有比较p1和p2指向的对象内容,而比较的是p1和p2指针的地址,这就无法达到预期而错误。

那如果我们就想比较日期,即使我们拿到的是date*的指针,我们也想按日期去比较,怎么办?

🆗,我们在优先级队列那篇文章是不是解决过这个问题啊,可以写一个仿函数去搞定这个问题。
那除了仿函数,还有没有其它方法来解决呢?
有的,我们还可以使用模板特化去解决这个问题。

那模板特化到底是什么呢?

模板特化即在原模板的基础上,针对特殊类型所进行特殊化的实现
模板特化中分为函数模板特化类模板特化

3.2 函数模板特化

首先我们来看函数模板特化,我们说上面那种情况可以用模板特化去解决。

那现在问题来了,对于一个像上面那样的函数模板,我们想对其进行特化,要怎么做呢?或者说步骤是什么?

🆗,来看,函数模板特化的步骤:

  1. 必须要先有一个基础的函数模板

那这个我们已经有了啊

template<class T>
bool Less(T left, T right)
{
	return left < right;
}

接着要怎么做呢?
🆗,特化出来的版本是这样的:

  1. 关键字template后面接一对空的尖括号<>
  2. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
  3. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误

那我们现在要对Date*这种类型进行特化,所以函数名后面的尖括号里面放的就是Date*
在这里插入图片描述
那我们想要的是比较它们指向的日期的大小,所以现在函数体应该这样实现:
在这里插入图片描述
至此我们的特化就完成了。

那我们来试一下这次的结果是否正确:

在这里插入图片描述
🆗,这下结果就正确了。

我们实现了特化的版本之后:

对于那些普通的类型,就还是走普通版本的逻辑
在这里插入图片描述
而一旦遇到我们特化的类型,他就会走特化版本的逻辑。
在这里插入图片描述
所以模板特化就是针对某些特殊类型进行特殊化的处理。

当然,其实针对上面这种情况,我们不使用模板特化也能很轻松解决:

我们可以直接针对Date*这种类型,写一个函数出来啊:
在这里插入图片描述
在这里插入图片描述
这样也可以啊。
该种实现简单明了,代码的可读性高,容易书写。

是的,所以说:

函数模板不建议特化,一般情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都是将处理该情况的函数直接给出,而不是对其进行特化。
所以对于函数模板特化我们这里也不再继续介绍更多的内容了。

3.3 类模板特化

接下来我们再来学习一下类模板的特化:

首先我们要知道模板的特化其实分为两种——全特化和偏特化

3.3.1 全特化

全特化即将模板参数列表中所有的参数都确定化。

举个栗子,现在有这样一个类模板:

template<class T1, class T2>
class Data
{
public:
	Data() 
	{ 
		cout << "Data<T1, T2>" << endl; 
	}
private:
	T1 _d1;
	T2 _d2;
};

那我们现在想对这个类模板进行全特化,怎么做呢?

那就是把该类模板模板参数列表的所有参数都确定化嘛。
在这里插入图片描述

那此时如果我们实例化该类模板的时候:

在这里插入图片描述
如果我们指定的类型是<int, char>,那就匹配全特化的版本,因为我们的全特化就是把它确定成了<int, char>,那其它类型就匹配的是原始的版本。

3.3.2 偏特化

那什么是偏特化呢?
偏特化有以下两种表现方式:

部分特化
  1. 部分特化
    将模板参数类表中的一部分参数特化(确定化)

什么意思?举个栗子:

还是上面那个Data类模板
在这里插入图片描述
那我们想对它进行部分特化,比如把第二个参数特化成int,就是这样搞:
在这里插入图片描述
在这里插入图片描述

参数更进一步的限制
  1. 参数更进一步的限制
    针对模板参数更进一步的条件限制所设计出来的一个特化版
    本。

什么意思呢?举个栗子:
现在这里有一个用来进行小于比较的仿函数

template<class T>
struct Less
{
	bool operator()(const T& l, const T& r) const
	{
		return l < r;
	}
};

在这里插入图片描述

我们来用它比较一些内置类型数据的大小,包括我们的日期类(重载了><),都是没什么问题的。
当然如果我们比Date*的话,还是比较的是地址的大小,如果我们想让他比较指针指向的数据的大小,我们可以对Date* 这个类型进行一个特化(那在这里其实就是一个全特化)。

但是,如果我们不只针对Date*的指针,对于其它类型的指针,比较时我们也想去比较它们指向的内容,而不是地址。
那我们可以怎么做呢?难道对不同的指针类型都进行一个特化吗?

这显然是很麻烦的。
那我们此时就可以用偏特化的第二种形式——参数更进一步的限制来解决这个问题。

怎么做呢?
在这里插入图片描述

进行一个偏特化,将模板参数限制成T*,这样只要调用仿函数时传的数据是指针类型,都会去匹配偏特化的这个版本,对指针指向的内容进行比较,而不是存储的地址。

我们来运行看一下:
在这里插入图片描述
这下就可以了。
在这里插入图片描述

4. 模板分离编译

然后我们再来学习一个东西叫做模板分离编译。

大家还记不记得我们在模板初阶的学习中,文章最后我们提到一个东西,就是我们定义一个类可能习惯头文件和源文件分开来,那普通类这样搞是没问题的,就像我们之前实现的日期类就是多文件管理的。
但是呢,类模板不行,类模板如果这样搞,会链接错误的。

那这篇文章在这里,我们就会来解释一下其中的原因。

4.1 什么是分离编译

我们先来了解一下,什么是分离编译:

分离编译模式源于C语言,在C++语言中继续沿用。
简单地说,分离编译模式是指:一个程序(项目)由若干个源文件(或在加上若干头文件)共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件连接起来形成单一的可执行文件的过程。

4.2 模板的分离编译

假如有以下场景,模板的声明与定义分离开,在头文件中进行声明,源文件中完成定义:

在这里插入图片描述
除了模板函数之外,我还加了一个普通函数,也是声明定义分开。

然后我们在test.cpp的main函数中去调用模板函数和普通函数,我们会发现:

在这里插入图片描述
普通函数func分离编译时没问题的,可以正常调用,没有报错。
但是:
在这里插入图片描述
我们发现模板是不行的,它报了一个链接错误。

那为什么呢?为什么模板分离编译不行呢?

🆗,那我们接下来就来分析一个当前这个程序编译链接的一个过程(复习相关知识可看之前的这篇文章:【C进阶】——我们写的代码是如何一步步变成可执行程序(.EXE)的?),看能不能发现其中的原因。
那大致的过程呢差不多是这个样子的:
在这里插入图片描述
在里面这个编译的过程中,会把预处理之后的C++代码转换为汇编代码(由一系列汇编指令组成),而函数的地址信息其实就包含在这些汇编指令中。
但是呢,对于当前这个程序来说,编译(func.i——>func.s)的过程中,只会生成func函数的汇编指令,而并没有函数模板Add的。
因为Add没有被实例化,为什么没实例化呢,函数模板实例化不是在编译期间就会进行吗?
因为func.cpp和test.cpp是分开的,链接之前它们都是单独进行的,test.cpp里面指定了具体类型对Add进行实例化,但是func.cpp编译的时候没法确定类型,因为在链接之前它们不交互,所以func.cpp里面的函数模板没法确定T要替换成什么类型,所以没法实例化。
那然后我们再来分析一下,main函数中在调用它们的时候这个过程是怎么样的?
在这里插入图片描述
首先在test.c编译的过程中这几句代码肯定也会被变成汇编代码
在这里插入图片描述
那函数调用转换成对应的汇编代码其实就是去call这个函数的地址。
但是呢,test.c包含了头文件"func.h",而"func.h"里面只有Add和func的声明,并没有具体的函数定义和对应的实例化生成的具体函数,所以这里生成的符号表里面,它们的地址可能知识标识一下,无实际意义。
但是有声明的话这里编译也可以通过。
可是呢?后面链接的时候就有问题了:
我们知道连接的时候会做一件事情叫做符号表的合并和重定位,然后就可以拿到这些函数重定位之后有效的地址,就可以成功调用它们了。
那func函数在func.cpp中是有具体的定义的,所以最终的符号表中会有它有效的地址。
但是,由于Add并没有成功进行实例化,没有生成具体的函数定义,所以就找不到有效的地址,所以符号表合并和重定位之后,里面并没有有效的函数地址,可能还是声明产生的那个无效的,没有意义的地址
在这里插入图片描述
所以这里两个Add就无法调用,由于是在链接阶段出现的错误,所以报的错是链接错误error LNK
大家也可以看一下这张图:
在这里插入图片描述

那通过上面的分析我们可以得出:

其实模板分离编译导致出错的原因关键就在于这些多个文件是分离编译的,在链接之前它们是不会进行交互的,所以没法实例化,没法产生具体的函数或类,因为不交互的话,类型都没法确定。
所以最后链接的时候就没法找的有效的地址,就出现了链接错误。

4.3 解决方法

那针对上面的问题,有没有什么解决方法呢?
有的,这里有两种解决方法:

  1. 在模板定义的位置显式实例化

举个栗子:

在这里插入图片描述
对于Add这个模板,你在main函数里面不是实例化了两份嘛,一份是int,一份是double。
那我们就针对这两个在模板定义的位置显示实例化一下,怎么做呢?
在这里插入图片描述
写法是这样的。
然后我们再来运行:
在这里插入图片描述
就可以了。
但是我们发现,这种方法的,增加一个新类型,我们就要增加一个显式实例化,很麻烦。
所以不推荐这种方法。

那有没有好一点的方法呢?有的

  1. 声明和定义可以分离,但放到一个文件中

什么意思呢?

就是你可以把模板的声明和定义分开来写,但是不要分成一个头文件,一个源文件,而是把它们放到一个.h或者一个.hpp文件里面。(有的头文件为了暗示是模板会将后缀改成.hpp,但还是头文件)
在这里插入图片描述
在这里插入图片描述
这样就不会出错了。推荐使用这种。

所以如果遇到需要分离的场景建议大家使用第二种方式。

5. 模板总结

最后我们来对模板进行一个简单的总结:

5.1 优点

  1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
  2. 增强了代码的灵活性

5.2 缺点

  1. 模板会导致代码膨胀问题,也会导致编译时间变长
  2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误

关于模板的讲解就先到这里。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/679152.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于TF-IDF算法个人文件管理系统——机器学习+人工智能+神经网络(附Python工程全部源码)

目录 前言总体设计系统整体结构图系统流程图 运行环境模块实现1. 数据预处理2. 词频计算与数据处理3. 数据计算与对比验证 系统测试工程源代码下载其它资料下载 前言 本项目旨在通过应用TF-IDF算法&#xff0c;将新下载的课件进行自动分类整理。我们的方法是通过比较新文件中的…

Matlab统计分析-相关系数

统计分析-相关系数 相关系数 (pearson与spearman) 皮尔逊 person相关系数和斯皮尔曼spearman等级相关系数&#xff0c;它们可用来衡量两个变量之间的**(线性)**相关性的大小&#xff0c;根据数据满足的不同条件&#xff0c;我们要选择不同的相关系数进行计算和分析。 基础概…

C生万物 | 常见的六种动态内存错误

学习过C语言中的动态内存函数&#xff0c;例如【malloc】、【calloc】、【realloc】、【free】&#xff0c;那它们在使用的过程中会碰到哪些问题呢&#xff0c;本本文我们一起来探讨下~ 1、对NULL指针的解引用操作 代码&#xff1a; void test() {int *p (int *)malloc(INT_…

Sui链上事务处理概述

Sui通过其混合式交易处理方法&#xff0c;实现比其他区块链更快速和高效的性能。这种方法使得Sui的交易测试吞吐率达到每秒297,000次。从实际应用的角度来看&#xff0c;使用Sui的用户在apps和游戏中几乎能够获得实时响应。 在区块链世界中&#xff0c;交易是apps运作的基础&a…

AutoHotKey脚本的循环:While和Loop

While AHK提供三种循环方法&#xff0c;分别是Loop, While和For&#xff0c;其中While和For在其他语言中都很常见&#xff0c;下面通过while循环&#xff0c;实现一个鼠标框选矩形尺寸的脚本 ; 来自官网的案例 CoordMode "Mouse", "Screen"~LButton:: {M…

【文献分享】基于感知质量的滚动优化无人机导航

论文题目&#xff1a;Perception-aware Receding Horizon Navigation for MAVs 作者&#xff1a;Zhang, Zichao ; Scaramuzza, Davide 作者机构&#xff1a;苏黎世大学 论文链接&#xff1a;https://files.ifi.uzh.ch/rpg/website/rpg.ifi.uzh.ch/html/docs/ICRA18_Zhang.pd…

【雕爷学编程】Arduino动手做(122)---BH1750光照传感器

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

使用近10年,说说向大家推荐Linux系统的理由

使用linux已经快十年了&#xff0c;一直想推荐身边的使用linux,但是一直没有分享。但是现在我想分享推荐了。下面我们一起聊聊为什么我向大家推荐linux。 为什么现在我想推荐了呢&#xff1f;是因为我自认为相对于同龄人来说&#xff0c;我使用桌面版的时间算是挺长的了&#…

彻底搞懂什么是阿里云服务器vCPU?

阿里云ECS服务器vCPU和CPU是什么意思&#xff1f;CPU和vCPU有什么区别&#xff1f;一台云服务器ECS实例的CPU选项由CPU物理核心数和每核线程数决定&#xff0c;CPU是中央处理器&#xff0c;一个CPU可以包含若干个物理核&#xff0c;通过超线程HT&#xff08;Hyper-Threading&am…

走向计算机视觉的通用人工智能:从GPT和大型语言模型中汲取的经验教训 (下)...

点击蓝字 关注我们 关注并星标 从此不迷路 计算机视觉研究院 公众号ID&#xff5c;计算机视觉研究院 学习群&#xff5c;扫码在主页获取加入方式 论文地址&#xff1a;https://arxiv.org/pdf/2306.08641.pdf 计算机视觉研究院专栏 Column of Computer Vision Institute 人工智能…

Matlab预测模型-灰色预测模型

预测模型-灰色预测模型 灰色预测是对既含有已知信息又含有不确定信息的系统进行预测&#xff0c;就是对在一定范围内变化的、与时间有关的灰色过程进行预测。灰色预测对原始数据进行生成处理来寻找系统变动的规律&#xff0c;并生成有较强规律性的数据序列&#xff0c;然后建立…

Linux学习[19]管线命令详解1---cut, grep, sort, wc, uniq

文章目录 1. 何为管线2. 摘取命令&#xff1a;cut, grep2.1 cut2.2 grep 3. 排序命令sort,wc,uniq3.1 sort3.2 uniq3.3 wc 总结 1. 何为管线 管线命令和Linux学习18里面的连续执行指令少许不同。他是只有在前面指令执行正确的时候&#xff0c;才会执行管线命令。 即这个管线命…

基于Vue+Node.js的宠物领养网站的设计与开发-计算机毕设 附源码 83352

基于VueNode.js的宠物领养网站的设计与开发 摘 要 随着互联网大趋势的到来&#xff0c;社会的方方面面&#xff0c;各行各业都在考虑利用互联网作为媒介将自己的信息更及时有效地推广出去&#xff0c;而其中最好的方式就是建立网络管理系统&#xff0c;并对其进行信息管理。由…

彻底卸载mysql的详细步骤

目录 一、前言 二、操作步骤 &#xff08;一&#xff09; 停止mysql的服务 &#xff08;二&#xff09;控制面板卸载 &#xff08;三&#xff09;清除残留的文件 &#xff08;四&#xff09;删除注册表内容 &#xff08;五&#xff09;删除MySQL环境变量 一、前言 卸载…

spider-flow新手暴力入门

1.入口 链接跳转: spider-flow 或者本地有git软件直接输入gittt中的链接地址&#xff0c;回车键梭哈即可 2.环境部署&#xff0c;必备jdk8mysql idea打开项目&#xff0c;重点修改如下 mysql用小皮软件&#xff08;phpstudy&#xff09;自带的mysql5,navicat软件导入sql文…

SEO一般多久时间才会有效果?

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言什么是SEOSEO的时间…

Sui x KuCoin Labs夏季黑客松第二批入围项目公布

Sui x KuCoin Labs夏季黑客松仍在如火如荼地进行中。自第一批入围项目名单公布后一周&#xff0c;第二批入围项目现已经过审核&#xff0c;入围最终Demo Day。 第二批入围名单 Vimverse Vimverse是一个基于Sui构建的创新生态金融平台&#xff0c;旨在释放去中心化储备货币协…

计算物理专题:主值积分

计算物理专题&#xff1a;主值积分 吴式枢理论 主值积分 设在以及上可积&#xff0c;其中为任意小的正数&#xff0c;当两者独立地趋于零&#xff0c;极限存在。如果&#xff0c;这个极限存在&#xff0c;则称它为瑕积分的主值&#xff0c;记作无界函数的改造则该瑕积分的主值…

使用鲁棒优化的定价策略进行微电网不平衡管理研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

童安格杀猪和金钥匙-UMLChina建模知识竞赛第4赛季第7轮

DDD领域驱动设计批评文集 欢迎加入“软件方法建模师”群 《软件方法》各章合集 参考潘加宇在《软件方法》和UMLChina公众号文章中发表的内容作答。在本文下留言回答。 本轮每题分数较少&#xff0c;需最先答对所有4题&#xff0c;才能获得本轮优胜。 所有题目的回答必须放…