函数模板

1、什么是函数模板?

模版使用泛型来定义函数,泛型可以用具体的类型(如int、double等)替换。

(1)函数模板允许以任意类型的方式来定义函数

通过将类型作为参数传递给模板,可是编译器生成该类型的函数。——也称通用编程

(2)模板的好处

减少工作量。对于同一算法的不同数据类型实现,可以避免程序员多次手动编写、修改代码,进而避免了在修改代码时犯下的一系列错误。

(3)模板的应用

需要多个将同一种算法用于不同类型的函数,请使用模板。

(4)模板的局限性

编写的模板函数很可能无法处理某些类型。

(这里就有一个疑问,既然存在特殊化,干吗还要模板呢?直接用非模板的多好。)

// 举例
template <typename T>
void f(T a, T b){...if(a>b)...}
// 如果 T 是int,则if 判断语句是有意义的。那 T 换成数组、结构等呢?模板就失效了。

解决方法有2种:

  • C++重载运算符,以便能够将其用于特定的结构或类。
  • 为特定类型提供具体化的模板定义。

2、模板的使用方法

关键词 templatetypename 是必须的!(在C++98 标准及其以前,使用关键词 class 来代替 typename)

必须使用尖括号

在不同的文件(或转换单元)之间编程时,模板声明和定义的位置需要注意,有三种方案:

  • 在实例化要素中让编译器看到模板定义;
  • 用另外的文件来显式地实例化类型,这样连接器就能看到该类型。
  • 使用export关键字。

模板类的定义和声明为何要写在一起

/* 下面是一个模板的例子 */
/* 函数声明 */
template <typename T>         // 这里的 T 可以表示任意类型。函数声明需要这句话!
void lizi(T &a, T &b, int k);   // *** 模板函数中的参数,不一定必须都是模板参数类型!***
/* 函数定义 */
template <typename T>         // 这里的 T 可以表示任意类型。函数定义也需要这句话!
void lizi(T &a, T &b, int k){ T temp;   temp = a;  a = b + k;    b = temp; }

注意

(1)函数模板并不创建函数!而是告诉编译器在调用该函数时,应该根据实际使用的类型来定义函数,此时才算创建了函数。So,最终的代码不包含任何模板,只包含了为程序生成的实际函数

(2)考虑向低版本兼容的话,可以用 class 替换 typename

(3)常见的是把模板放在头文件中,在使用时包含头文件。

3、函数重载的模板

被重载的模板的函数特征标(参数列表)必须不同!

/* 下面是一个函数重载的模板的例子 */
template <typename T>
void swap(T &a, T &b);
template <typename T>
void swap(T *a, T *b, int n);

4、具体化和实例化

(1)显式具体化的模板函数:

提供一个具体化的函数模板,包含所需的代码。当编译器找到与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板。

显式具体化声明在关键字 template 后包含 <>,而显式实例化没有。

template <>
void swap<int>(int &, int &); // 显式具体化
template <>
void swap(int &, int &);        // 显式具体化

(2)显式实例化的模板函数:(这一部分知识点存疑,待定)

  • 直接命令编译器创建特定的实例。其语法是,声明所需的种类——用<>符号指示类型,并在声明前加上关键字 template
template void swap<int>(int, int); // 显式实例化
  • 还可通过在程序中使用函数来创建显式实例化。
template <class T>
T Add(T a,T b){return a + b;}
int m=6;
double x = 10.2;
cout << Add<double>(x, m)<< endl; // 显式实例化

这里的模板 Add(T a,T b) 与函数调用 Add(x,m) 不匹配,因为该模板要求两个函数参数的类型相同。但通过使用 Add(x, m),可强制为double 类型实例化,并将参数m强制转换为double 类型,以便与函数 Add(double, double)的第二个参数匹配。

注意:

试图在同一个文件(或转换单元)中使用同一种类型的显式实例和显式具体化将出错

禁止在main函数中进行实例化。

(3)隐式实例化的模板函数:

编译器通过模板生成的函数定义。

#include<iostream>
#include<string>
using namespace std;struct job {int jobname = 0;int jobnum = 0;
};
template <typename T>
void myswap(T&, T&);    // 普通模板
template <typename T>
void myswap(T& a, T& b) {T c = a;a = b;b = c;
}
template <> void myswap<job>(job &, job &); // 显式具体化
template <> void myswap<job>(job& job1, job& job2) {int i = job1.jobname;int j = job1.jobnum;job1.jobname = job2.jobname;job1.jobnum = job2.jobnum;job2.jobname = i;job2.jobnum = j;
}
template <> void myswap<char>(char&, char&);
template <> void myswap<char>(char& c, char& d) {char e = c;c = d + 1;d = e + 1;
}
int main()
{short a = 21, b = 19;cout << "a=" << a << ";" << "b=" << b << endl;myswap(a, b);                                 // 隐式实例化cout << "a=" << a << ";" << "b=" << b << endl;job job1 = { 11, 11 };job job2 = { 22, 22 };cout << "job1.name=" << job1.jobname << ";" << "job2.name=" << job2.jobname << endl;myswap(job1, job2);cout << "job1.name=" << job1.jobname << ";" << "job2.name=" << job2.jobname << endl;char c = 'a';char d = 'b';cout << "c=" << c << ";" << "d=" << d << endl;myswap(c, d);cout << "c=" << c << ";" << "d=" << d << endl;return 0;
}

5、 选择哪个函数版本呢?

(1)对于函数重载、函数模板、函数模板重载,C++的一个策略是重载解析

1️⃣创建候选函数列表:包括同名函数和模板函数;

2️⃣在候选函数列表中创建可行函数列表:这些都是参数数目正确的函数,为此有一个隐式转换序列,其中当然也包括完全匹配的情况。

3️⃣确定是否有最佳的可行参数。最佳到最差的顺序:

  • 完全匹配——要考虑到常规函数优于模板。
  • 提升转换——(例如:char、short转换为int,float转换为double)
  • 标准转换——(例如:int转换为char,long转换为double)
  • 用户定义的转换,如类声明中定义的转换。

(2)完全匹配和最佳匹配

struct blot {int a; char b[10];};
blot ink = {25,"spots"};
recycle(ink);
// 在这种情况下,下面的原型都是完全匹配的:
void recycle(b1ot);         // #1 blot-to-blot
void recycle(const blot);   // #2 blot-to- (const blot)
void recycle(blot &);       // #3 blot-to- (blot &)
void recycle(const blot &); // #4 blot-to- (const blot &)
  • 如果有多个匹配的原型,无法确定最佳的可行函数,就会报错:ambiguous,二义性。
  • 有例外:两个函数都完全匹配,仍可完成重载解析:**指向非常量数据的指针、引用,可以优先的与非常量指针、引用参数匹配。**在上面的例子里,如果只定义了函数#3和#4,则将选择#3,因为 ink 没有被声明为 const 。如果只定义了函数#1和#2,则将出现二义性。
  • 一个完全匹配优于另一个的另一种情况是:
    • 其中一个是模板函数,而另一个不是。在这种情况下, 非模板函数将优先于模板函数(包括显式具体化)。
    • 如果两个完全匹配的函数都是模板函数,则较具体的模板函数优先。例如,这意味着显式具体化将优于使用模板隐式生成的具体化。较具体的意思是,编译器在推断使用哪种类型时执行的转换最少。
template <c1ass Type> void recycle (T t);  // #1
template <class Type> void recycle (T *t);    // #2
struct blot {int a; char b[10];};
blot ink = {25,"spots"};
recycle(&ink);
// 假设recycle(&ink)调用与#1的模板匹配,匹配时将T解释为 blot*
// 假设recycle(&ink)调用与#2的模板匹配,匹配时将T解释为 blot
// 在 #2 的模板中,T已经被具体化为指针,因此说它更具体。

(3)自己选择

自己编写合适的函数调用,引导编译器作出自己希望的选择。

将模板函数定义放在文件开头,从而无需提供模板原型。

template<class T>              // or template <typename T>
T lesser(T a,T b){……}           // #1
int lesser(int a, int b){……}    // #2
int main(){int m = 20; int n = -30; double x = 15.5; double y = 25.9;lesser(m,n);       // 调用#2lesser(x,y);     // 调用#1,T为doublelesser<>(m,n);     // 调用#1,T为intlesser<int>(x,y); // 调用#1,T为int,double型的x和y被强制转换
}

lesser<>(m,n);中的 <> 指出:编译器应选择模板函数,而不是非模板函数。

6、 模板函数的发展

C++98标准:

  • 对于给定的函数名,可以有非模板函数、模板函数、显式具体化模板函数以及它们的重载版本。
  • 显式具体化的原型和定义应以 template<> 打头,并通过名称来指出类型。
  • 具体化优先于常规模板,而非模板函数优先于具体化和常规模板。

缺陷:

template<class T1, class T2>
void ft(Tl x,T2 y){...?type? xpy=x+y;...
} // 在不知道 T1 和 T2 的类型时,很难确定 xpy 的类型。可能是T1,T2或者其他类型。

C++11新增的关键字:decltype

int x;
decltype(x) y;      // 使得 y 的类型和 x 的类型一样
decltype(y+y) xpy; // 给decltype的参数可以是表达式,包括算术表达式、函数调用等

实际上,decltype 的原理要复杂的多:为了确定参数的类型,编译器必须遍历一个核对表:(简化)

对于:decltype(expression) var;

1️⃣如果 expression 是一个没有用括号括起的标识符(decltype本身的括号不算),则 var 的类型与 expression 类型相同,包括 const 等限定符。

double x = 5.5;
double y = 7.9;
double &rx = x;
const double * pd;
decltype(x) w;          // w is type double
decltype(rx) u = y;        // u is type double &
decltype(pd) v;         // v is type const double *

2️⃣如果 expression 是一个函数调用,则 var 的类型与函数的返回类型相同。

注意:这个过程中,并不会真正的去调用函数,只是会查看函数的原型以获得返回类型。

long indeed(int) ;
decltype (indeed(3)) m; // m is type int

3️⃣如果 expression 是一个左值,则 var 为指向其类型的引用。

注意!此处已经是第三步了,我们是从第一步开始判断的,符合条件就结束了~所以啊,这里进入第三步的情况是:当expression 是用括号括起来的标识符:

double xx = 4.4;
decltype((xx)) r2 = xx;        // r2 is double &
decltype(xx) w = xx;       // w is double (此种情况在第一步就判断出来了)
// 括号并不会改变表达式本身的性质。
double (xx) = 4.4;     // 等价于 double xx = 4.4;

4️⃣如果前面的条件都不满足,则 var 的类型与 expression 的类型相同:

int j = 3;
int &k = j
int &n = j;
decltype(j+6) i1;  // i1 type int
decltype(100L) i2;  // i2 type 1ong
decltype(k+n) i3;  // 13 type int;
// 虽然 k 和 n 都是引用。但表达式 k+n 却不是引用,它是两个int的和,因此类型为 int。

C++11后置返回类型

auto 新增的一个功能。

decltype 的缺陷:无法预先知道将 x 和 y 相加得到的类型。

template<class Tl, class T2>
?type? gt(Tl x,T2 y){...return x + y;
}
// 新增语法
double h(int x, float y);
auto h(int x, float y) -> double;    // 将返回类型移到参数声明的后面。
auto h(int x, float y) -> double{    // 这种语法也可用于函数定义……
}
  • ->double 被称为后置返回类型。

  • auto 是一个占位符,表示后置返回类型提供的类型。

通过结合使用这种语法和 decltype ,便可指定返回类型:

template<class T1, class T2>
auto gt(T1 x, T2 y) -> decltype(x + y){...return x + y;
}

类模板

1、定义类模板

template<class Type> class ClassName{}     // 旧版本,用 class
template<typename Type> class ClassName{} // 新版本,用 typename 避免与类的关键词class 混淆

Type 是一个通用的类型说明符,模板被调用(实例化)时,Type 将具体的类型值代替。

可以使用模板成员函数替换原有类的类方法,要求:每个函数头都将以相同的模板声明打头,且类限定符也需要加上 。当然,在类中定义,限定符和模板前缀都可以省略!

template<typename Type> class ClassName{public:bool push(const Type &);// bool push(const Type & item){……}
}
// bool ClassName::push(const Type & item){……}
template<typename Type> bool ClassName<Type>::push(const Type & item){……}

模板不是函数,它不能单独编译,模板必须与特定的模板实例化请求一起使用。

由于C++11中不再支持 export 以前的功能,不能将模板成员函数放在独立的实现文件中,最简单的方法就是将所有模板信息放在一个头文件中,并在要使用这些模板的文件中包含该头文件。

2、使用模板类

需要声明一个类型为模板类的对象,方法是使用显式地所需要的具体类型替换泛型名(类型参数,如此处的Type)

格式:类名 <具体的类型参数1, 具体的类型参数2, …> 该类的实例化对象名;

【注】和模板函数的区别,必须是显式地。

3、深入探讨模板类

(1)使用指针栈(指针作为类型参数)

方法:让调用程序创建一个指针数组,其中每个指针都指向不同的字符串。栈的任务是管理指针,而不是创建指针。

(2)数组模板示例和非类型(也称:表达式)参数

Q:如何创建一个允许指定数组大小的简单数组模板?

  1. 方法一:在类中使用动态数组和构造函数参数来提供元素数目;
  2. 方法二:使用模板参数来提供常规数组的大小。
// Array 模板
#include<iostream>
#include<cstdlib>template<class T, int n> class ArrayTP{private:T ar[n];public:ArrayTP(){};explicit ArrayTP(const T & v);virtual T & operator[](int i);virtual T operator[](int i) const;}template<class T, int n> ArrayTP<T,n>::ArrayTP(const T & v){for(int i=0; i<n; i++) ar[i] = v;}template<class T, int n> T & ArrayTP<T,n>::operator[](int i){if(i<0 || i>=n){std::cerr<<"错误,下标: "<< i << " 越界了"<<std::endl;std::exit(EXIT_FAILURE);}return ar[i];}
template<class T, int n> T ArrayTP<T,n>::operator[](int i)const{if(i<0 || i>=n){std::cerr<<"错误,下标: "<< i << " 越界了"<<std::endl;std::exit(EXIT_FAILURE);}return ar[i];
}

template<class T, int n> 中的 int n 这种参数(指定特殊的类型而不是用作泛型名)称为非类型表达式参数

  • 表达式参数有一些限制:

    • 可以是整型、枚举、引用或指针,如double就不可以,而double*可以。
    • 不可以是表达式,如n++,&n等。
    • 实例化模板时,用作表达式参数的值必须是常量表达式。
  • 优点:为自动变量维护内存占栈,而不是使用new出来的堆上内存。

  • 缺点:每种数组大小都将生成自己的模板。下面的声明将生成两个独立的类声明:

ArrayTP<double, 12>eggweights;
ArrayTP<double, 13>donuts;

4、模板的多功能性

(1)模板类可用作基类、组件类、其他模板的类型参数

template<typename T> class Array{private:T entry;...
};template<typename Type> class GrowArray: pulic Array<Type>{...};  // 基类,继承
template<typename Tp> class Stack{    Array<Tp> ar;                                             // 组件类...
};
...
Array<Stack<int>> asi;                                          // 用作其他模板类

上面最后一句代码:C++98中,要求至少使用一个空白字符将两个 > 符号分开,以免与运算符 >> 混淆,C++11则不要求。

(2)可以递归使用模板

vector<vector<int>> a;

(3)使用多个类型参数

#include<iostream?
#include<string>
template<class T1, class T2> class Pair{private:T1 a;T2 b;
public:T1 & first();T2 & Second();T1 first() const{return a;}T2 Second() const{return b;}Pair(const T1 & aval, const T2 & bval):a(aval), b(bval){}Pair() {}
};
template<class T1, class T2> T1 & Pair<T1,T2>::first(){return a;}
template<class T1, class T2> T2 & Pair<T1,T2>::Second(){return b;}
int main(){using std::cout;using std::endl;using std::string;Pair<string, int> rating[2] = {             // 类名是 Pair<string, int>Pair<string, int>("1", 1);                // 而不是 PairPair<string, int>("2", 2);               // Pair(char*, double)是另一个完全不同的类名称};int joints = sizeof(ratings)/sizeof(Pair<string, int>);...return 0;
}

(4)默认类型模板参数

template<class T1, class T2 = int> class Topo{...};
// 如果省略 T2 的值,编译器将使用 int
Topo<double, double> m1;  // T1 为 double, T2 为 double;
Topo<double> m2;          // T1 为 double, T2 为 int;

5、模板的具体化

具体化:隐式实例化、显式实例化、显式具体化。

模板以泛型的方式描述类,具体化是使用具体的类型生成类声明。

(1)隐式实例化

声明一个或多个对象,指出所需的类型,而编译器使用通用模板提供的处方生成具体的类定义。

ArrayTP<double, 30> *pt;           // 隐式实例化.编译器在需要对象前,不会生成类的隐式实例化:
pt = new ArrayTP<double, 30>;/        // 现在需要了

(2)显式实例化

当使用关键字 template 并指出所需类型来声明类时,编译器将生成类声明的显式实例化。

声明必须位于模板定义所在的名称空间中。

template class ArrayTP<string, 100>;   // 生成 ArrayTP<string, 100> 类

在这种情况下,虽然没有创建或提及类对象,编译器也将生产类声明(包括方法定义)。

(3)显式具体化

是特定类型(用于替换模板中的泛型)的定义。因为有时候需要为特殊类型修改模板,所以索性单独显式的具体化。具体化模板定义的格式:

template <> class ClassName<specialized-type-name>{...};
// 通用模板
template<typename T>class SortedArray{...};
// 显式具体化
template <> class SortedArray<const char*>{...};

(4)部分具体化

部分限制模板的通用性。可以给类型参数之一指定具体的类型:

template<class T1, class T2> class Pair{...};      // 通用模板
template<class T1> class Pair<T1, int>{...};        // 部分具体化

☆ 从这里可以看出:template 后面尖括号<>里的类型参数是没有被具体化的,具体化的写在后面

  • 如果有多个模板可供选择,具体化程度越高,越优先选择;
Pair<double, double> p1;
Pair<double, int> p2;
pair<int, int> p3;
  • 可以通过为指针提供特殊版本来部分具体化现有的模板;
template<class T> class Feeb{...}; // 通用模板
template<class T*> class Feeb{...};   // 指针具体化版本
Feeb<char> fb1;                       // 使用通用模板,其中 T = char
Feeb<char *> fb2;                 // 使用指针具体化版本,其中 T = char
  • 部分具体化能够设置各种限制:
template <class T1, class T2, class T3> class Trio{...};      // 1
template <class T1, class T2> class Trio<T1, T2, T2>{...};     // 2
template <class T1> class Trio<T1, T1*, T1*>{...};            // 3
Trio<int, short, char*> t1;                               // 使用 1 通用模板
Trio<int, short, short> t2;                               // 使用 2 Trio<T1, T2, T2>
Trio<char, char*, char*> t3;                          // 使用 3 Trio<char, char*, char*>

6、成员模板

模板可用作结构、类或模板类的成员。

template <typename T> class beta{private:template <typename V> class hold{             // 模板类private:V val;public:hold(V v=0):val(v){};void show() const{cout<<val<<endl;}V value() const{return val;}};hold<T> q;                                  // 模板对象hold<int> n;
public:beta(T t, int i):q(t), n(i){}template <typename U> U blab(U u, T t){           // 模板成员函数return (n.value() + q.value()*u/t;)}void Show() const{...};
}

7、将模板用作参数

模板新增特性,用于实现STL。

template< template<typename T> class Thing> class Crab{};

8、模板类友元

模板类声明可以有友元。模板的友元分三类:非模板友元;约束模板友元;非约束模板友元。

(1)非模板友元

(2)约束模板友元

(3)非约束模板友元

9、模板别名(C++11)

可使用 typedef 为具体化后的模板指定别名:

typedef std::array<double, 12> arrd_12;
typedef std::array<int, 12> arri_12;
typedef std::array<std::string, 13> arrstr_13;
arrd_12 name1;                                  // name1 是类型 std::array<double, 12>
arri_12 name2;                                  // name2 是类型 std::array<int, 12>
arrstr_13 name3;                                // name3 是类型 std::array<std::string, 13>

C++11新增了:使用模板提供一系列别名:

template<typename T> using arrtype = std::array<T,12>;  // array<T> 表示类型 array<T, 12>
arrtype<int> name1;                               // name1 是类型 std::array<int, 12>
arrtype<double> name2;                            // name2 是类型 std::array<double, 12>
arrtype<std::string> name3;                       // name3 是类型 std::array<std::string, 12>

C++11允许将 using = 用于非模板,用于不是模板的情况时,该语法与常规 typedef 等价:

typedef const char* pc1;
using pc2 = const char*;   // pc1 和 pc2 都是 const char*

10、可变参数模板(C++11)

即:可接受可变数量的参数

要创建可变参数模板,需要理解4个要点:1、模板参数包2、函数参数包3、展开参数包4、递归

1、模板参数包 和 函数参数包

元运算符:用省略号表示。

  • 能够声明表示模板参数包的标识符,模板参数包基本上是一个列表(类型列表);
  • 能够声明表示函数参数包的标识符,函数参数包基本上是一个列表(值列表)。
template<typename T> void show_list0(T t);      // 通用模板函数
template<typename... Args>                        // Args 是一个模板参数包
void show_list1(Args... args)                   // args 是一个函数参数包
{...}

Args 和 T 的差别在于:T 只与一种类型匹配,而 Args 可以与任意数量(包括零个)的类型匹配

// 调用 show_list1 时:
show_list1(2, 4, 6, "who we are", string("appreciate"));

上述

C++ Primer Plus 学习笔记——模板相关推荐

  1. C++ Primer Plus 学习笔记(第 4 章 复合类型)

    C++ Primer Plus 学习笔记 第 4 章 复合类型 数组 数组(array)是一种数据格式,能够存储多个同类型的值. 要创建数组,可使用声明语句.数组声明应指出以下三点: 存储在每个元素的 ...

  2. 设计模式学习笔记——模板(Template)模式

    设计模式学习笔记--模板(Template)模式 @(设计模式)[设计模式, 模板模式, template, 模板方法] 设计模式学习笔记模板Template模式 基本介绍 模板案例 类图 实现代码 ...

  3. 整理:C primer plus 学习笔记

    前言:简单看了一遍C Primer Plus, 整理了一下,因为时间比较少,自己理解地比较肤浅,所以第一版比较简陋. 假期的时候应该会有时间再整理一下.------2018/11/5 2019/1/2 ...

  4. 图论01.最短路专题_学习笔记+模板

    图论01.最短路专题_学习笔记+模板 一.定义与性质 ● 需要的前导知识点 路径 最短路 有向图中的最短路.无向图中的最短路 单源最短路.每对结点之间的最短路 ● 最短路的性质 对于边权为正的图,任意 ...

  5. C++学习笔记:模板

    C++学习笔记:模板 1.函数模板 2.类模板 2.1类模板注意事项 2.2类模板中函数的创建时机 2.3类模板对象作函数参数时 2.4类模板与继承 2.5类模板分文件编写 2.6类模板友元 2.6. ...

  6. C++模板学习笔记——模板实参

    对于函数模板,编译器通过隐式推断模板实参.其中,从函数实参来确定模板实参的过程被称为模板实参推断.在模板实参推断过程中,编译器使用函数调用中的实参类型来寻找模板实参,用这些模板实参生成的函数版本与给定 ...

  7. C++ Primer Plus学习笔记之函数探幽

    前言 个人觉得学习编程最有效的方法是阅读专业的书籍,通过阅读专业书籍可以构建更加系统化的知识体系. 一直以来都很想深入学习一下C++,将其作为自己的主力开发语言.现在为了完成自己这一直以来的心愿,准备 ...

  8. image是否有disabled属性_Vue学习笔记 模板语法、计算属性

    点击上方"蓝字"关注我们吧! vue学习笔记 官网:https://cn.vuejs.org/v2/guide/ 1.vue体验 demo示例: image.png 示例代码: & ...

  9. C++ Primer Plus学习笔记之类和动态内存分配

    前言 个人觉得学习编程最有效的方法是阅读专业的书籍,通过阅读专业书籍可以构建更加系统化的知识体系. 一直以来都很想深入学习一下C++,将其作为自己的主力开发语言.现在为了完成自己这一直以来的心愿,准备 ...

  10. C++ Primer plus学习笔记-第十六章:string类和标准模板库

    第十六章:string类和标准模板库 前言:这一章已经相当靠近全书的后面部分了:这一章我们会深入探讨一些技术上的细节,比如string的具体构造函数,比如适用于string类的几个函数,比如我们还会介 ...

最新文章

  1. mysql二进制日志管理_MYSQL二进制日志管理脚本
  2. linux 系统创建ora文件,手动创建oracle数据库
  3. HDU 1026 Ignatius and the Princess I 迷宫范围内的搜索剪枝问题
  4. UA MATH566 统计理论1 充分统计量例题答案1
  5. Linux环境下Redis安装配置步骤
  6. Java中的Map List Set等集合类
  7. 深圳三防手持终端供应商×××
  8. python2.7_call
  9. 微信支付开发之APP支付介绍及业务流程
  10. 关于将网易有道词典单词本导出到必应词典生词本的尝试
  11. apple tv 开发_如何在新的Apple TV上重新排列,配置和删除应用程序和游戏
  12. edp和edt哪个好_香水edt和edp是什么意思
  13. python画图方法_python画图的两种方法
  14. 达梦数据库如何把EXCEL的数据导入到表中?
  15. 苹果支付成功后,JAVA服务端二次验证
  16. php单击回复出现回复框,javascript - 评论回复框的显示与隐藏问题
  17. Oracle数据库怎么调大字体,CFree怎么调大字体 设置字体大小的方法
  18. MMKV:微信团队开源的轻量级存储方案
  19. IDEA 设置代码提示或自动补全的快捷键
  20. STM32标准库的引入视频课程-第3季第6部分-朱有鹏-专题视频课程

热门文章

  1. wordpress使用Akismet Anti-Spam插件教程-防止垃圾评论
  2. 解决could not read ok from ADB Server.failed to start daemon error: cannot connect to daemon的问题
  3. 2017清华计算机夏令营机试题目,2017 ECNU计算机系暑期夏令营机考 eoj3307. 送分题...
  4. 【清华夏令营模拟2019.5.22】连续段(析合树+多项式牛顿迭代)
  5. 无论男女,永远不要去“追”一个人
  6. 章丘AAA企业信用评级申请条件和流程
  7. unity 背包系统格子排序组件
  8. 教学反思计算机专业,职业中学计算机专业教学反思
  9. 【K8S系列】第六讲:Kubernetes的网络模型
  10. [2018-10-17]宁波dotnet社区(NBDNC)第一次问卷关于dotnet技术栈的小调查