c/c++开发,无可避免的模板编程实践(篇二)
一、开发者需要对模板参数负责
1.1 为您模板参数提供匹配的操作
在进行模板设计时,函数模板或类模板一般只做模板参数(typename T)无关的操作为主,但是也不见得就不会关联模板参数自身的操作,尤其是在一些自定义的数据类型作为模板参数传入时。
看下面这段代码,在v1<v2时,就调用了标准库里的operator<操作符比较函数,由于typename T是std::string,在string类本身是支持了值比较的,因此调用正常。
template <typename T>
inline T mymin(const T &v1, const T &v2)
{return (v1<v2)?v1:v2;
};//会调用bool operator<(const T& obj1, const T& obj2)操作符函数"<"
mymin<std::string>("guangzhou","shenzhen");
那现在再来调整一下代码,自定义数据类型DataTest,其包含两个int型成员变量,现在将该类型作为模板参数传递给mymin函数时,会编译异常,提示并不支持operator<,虽然int型支持operator<,但两个int型的组合在一起就需要模板使用者来为模板参数(typename T)操作行为负责:
class DataTest
{
public:DataTest(const int &id_d,const int &id_p) : id_domain(id_d),id_point(id_p){};~DataTest(){};int id_domain;int id_point;
};//
DataTest adt(3,4),bdt(3,6);
mymin<DataTest>(adt,bdt);    //error, no match for 'operator<'为此,我们就需要给DataTest定义其operator<操作支持了
class DataTest
{
public:DataTest(const int &id_d,const int &id_p) : id_domain(id_d),id_point(id_p){};~DataTest(){};int id_domain;int id_point;
};
inline bool operator<(const DataTest& obj1, const DataTest& obj2) 
{ if(obj1.id_domain<obj2.id_domain)return true;if(obj1.id_domain==obj2.id_domain&&obj1.id_point<obj2.id_point)return true;return false;
};//
DataTest adt(3,4),bdt(3,6);
mymin<DataTest>(adt,bdt);    //OK, find 'operator<' success1.2 模板嵌套-类模板作为模板参数
再进一步深化一下代码设计,如果给函数模板mymin传递一个类模板A_Test呢,同样地为A_Test提供operator<操作支持,又会怎样。
template <typename T1, typename T2>
class A_Test
{
public:A_Test(const T1 &id_d,const T2 &id_p) : id_domain(id_d),id_point(id_p){};~A_Test(){};T1 getDomainID() const{return id_domain;};T2 getPointID() const{return id_point;};
private:T1 id_domain;T2 id_point;
};template <typename T1, typename T2>
inline bool operator<(const A_Test<T1,T2>& obj1, const A_Test<T1,T2>& obj2) 
{ if(obj1.getDomainID()<obj2.getDomainID()) return true;if(obj1.getPointID()==obj2.getPointID()&&obj1.getPointID()<obj2.getPointID()) return true;return false;
};
//
A_Test<int,float> a(3,4.2),b(2,3.8);
mymin<A_Test<int,float> >(a,b);    //OK,没什么区别,只是换成特例化类模板1.3 友元模板
在外部由于operator<是放置在类声明体外声明与定义的,它就不能直接使用类模板内的成员变量,就需要为它提供额外的访问函数getDomainID、getPointID,这样转一手的操作显然不符合inline的诉求,其实在标准库里,通常类模板会operator<声明友元函数,函数或类被声明为友元后,在类模板内就是真不把自身当外人了,甚至是类模板的儿子(派生类)都比不上。
为了区别前面一种方法,我们重新定义一个函数模板mymax,在类模板会operator>声明友元函数,看下列代码:
template <typename T1, typename T2>
class A_Test
{
public:A_Test(const T1 &id_d,const T2 &id_p) : id_domain(id_d),id_point(id_p){};~A_Test(){};//template <typename T> friend bool operator>(const T& obj1, const T& obj2); //why is eroortemplate <typename T3, typename T4>friend bool operator>(const A_Test<T3,T4>& obj1, const A_Test<T3,T4>& obj2);
private:T1 id_domain;T2 id_point;
};//
template <typename T1, typename T2>
inline bool operator>(const A_Test<T1,T2>& obj1, const A_Test<T1,T2>& obj2) 
{ if(obj1.id_domain<obj2.id_domain)    //直接访问私有成员不含糊return true;if(obj1.id_domain==obj2.id_domain&&obj1.id_point<obj2.id_point)      //直接访问私有成员不含糊return true;return false;
};//
template <typename T>
inline T mymax(const T &v1, const T &v2)
{return (v1>v2)?v1:v2;
};
//
A_Test<int,float> a(2,4.2),b(2,3.8);
mymin<A_Test<int,float> >(a,b);        //OKA_Test<std::string,std::string> a_s("guangzhou","huangpu"),b_s("shenzhen","baoan");
if(a_s<b_s);    //OK
if(a_s>b_s);    //OK,两者都可以实现,不看operator内部实现的话1.4 节省模板的配套操作
当然在实际设计中,我们最好还是避免同一模板的多个实例化中隐含的编译进开销:
template <typename T1, typename T2>
inline bool operator>(const A_Test<T1,T2>& obj1, const A_Test<T1,T2>& obj2) 
{ if(obj1.id_domain<obj2.id_domain)return true;if(obj1.id_domain==obj2.id_domain&&obj1.id_point<obj2.id_point)return true;return false;
};template <typename T>
inline T mymax(const T &v1, const T &v2)
{return (v1>v2)?v1:v2;
};//
template <typename T>
inline T mymin(const T &v1, const T &v2)
{return (v1>v2)?v2:v1;            //这样同样也能达成效果
};1.5 有度地规划类模板操作符
在设计类模板时需要慎重并认真地思考如何支撑一些通用的操作符调用,因为往往类模板设计者和使用者往往不会是同一个作者,那么使用者对待类模板时,会习惯性地把普通类型的调用习惯用到类模板上来设计其代码时,缺发现其实并不支持。例如,对于一个常规数据类型,输出显示是没有问题的,但是对于自定义的类模板,那就要想到使用者会有这样的用法习惯,给与到支持。
std::cout << mymin<std::string>("guangzhou","shenzhen") << std::endl;A_Test<int,float> a(3,4.2),b(2,3.8);
std::cout << mymin<A_Test<int,float> >(a,b) << std::endl; //error那么这些常用的一些操作函数,还是需要通盘考虑和设计的,当然使用者如果谨慎,他也应该明确知道模板参数行为需要使用者本身去把控。
template <typename T1, typename T2>
class A_Test
{
public:A_Test(const T1 &id_d,const T2 &id_p) : id_domain(id_d),id_point(id_p){};~A_Test(){};template <typename T3, typename T4>friend std::ostream &operator<<(std::ostream &os, const A_Test<T3,T4>& obj);
private:T1 id_domain;T2 id_point;
};//
template <typename T1, typename T2>
inline std::ostream &operator<<(std::ostream &os, const A_Test<T1,T2>& obj)
{os << "(";os << obj.id_domain << "," << obj.id_point;os <<")";return os;
};
//
A_Test<int,float> a(2,4.2),b(2,3.8);
std::cout << mymin<A_Test<int,float> >(a,b) << std::endl;    //OK
//
A_Test<std::string,std::string> a_s("guangzhou","huangpu"),b_s("shenzhen","baoan");
std::cout << mymin<A_Test<std::string,std::string> >(a_s,b_s) << std::endl; //OK
std::cout << mymax<A_Test<std::string,std::string> >(a_s,b_s) << std::endl; //OK1.7 按需增加必要支持
当然如何把控是模板设计的度,都是设计者及使用者的考验,例如,想更进一步使用上述的模板函数和类模板:
A_Test<DataTest,DataTest> ad_s(DataTest(3,4),DataTest(4,1)),bd_s(DataTest(2,4),DataTest(3,1));std::cout << mymin<A_Test<DataTest,DataTest> >(ad_s,bd_s) << std::endl;
std::cout << mymax<A_Test<DataTest,DataTest> >(ad_s,bd_s) << std::endl;显然,针对DataTest,我们需要重新去设计其在上层调用涉及到的<、>、== 这三个操作符函数声明定义后,才能被A_Test类模板和mymin、mymax函数模板所识别使用。
inline bool operator<(const DataTest& obj1, const DataTest& obj2) 
{ if(obj1.id_domain<obj2.id_domain)return true;if(obj1.id_domain==obj2.id_domain&&obj1.id_point<obj2.id_point)return true;return false;
};inline bool operator>(const DataTest& obj1, const DataTest& obj2) 
{ if(obj1.id_domain>obj2.id_domain)return true;if(obj1.id_domain==obj2.id_domain&&obj1.id_point>obj2.id_point)return true;return false;
};inline bool operator==(const DataTest& obj1, const DataTest& obj2) 
{ if(obj1.id_domain!=obj2.id_domain)return false;if(obj1.id_point!=obj2.id_point)return false;return true;
};二、模板隐藏的那些事
2.1 成员函数或成员变量的模板参数
类模板内的成员函数或成员变量类型都可以具有自己的模板参数。
template <typename T>
class OUT_Class
{
public:void myfun1(const T& obj);    //和外围模板使用同一个模板参数template <typename T1>void myfun2(const T1& obj);    //自定义了自己的模板参数
};template <typename T>
void OUT_Class<T>::myfun1(const T& obj)
{std::cout << obj << std::endl;
};template <typename T>    //主类的模板参数
template <typename T1>   //子类的模板参数
void OUT_Class<T>::myfun2(const T1& obj)
{std::cout << obj << std::endl;
};OUT_Class<int> o_a;
o_a.myfun1(10);
o_a.myfun2<double>(10.5);模板在外部定义时,具有多个模板参数语句template <typename ***>,一个语句用于自身,另一个语句用于外围模板,语句测顺序是从外围到内部的。
类模板内的函数模板 或类模板可以在主类模板内部定义,也可以放置外部定义。若是函数模板在类内部定义,则是一个显式内联函数。
//
template <typename T>
class OUT_Class
{
pbulic:template <typename T1>class INT_Class1	//内部直接定义{public:T1 val;};template <typename T1>class INT_Class2;	//外部定义
};//
template <typename T>
template <typename T1>
class OUT_Class<T>::INT_Class2
{public:T1 val;	
};//
OUT_Class<int>::INT_Class1<float> o_a_i1;
o_a_i1.val = 11.4;
OUT_Class<int>::INT_Class2<float> o_a_i2;
o_a_i2.val = 12.4;2.2 联合(Union)模板
模板设计还允许联合(Union)模板的存在:
template <typename T>
union Chunk
{T obj;unsigned char bytes[sizeof(T)];
};//
union Chunk<int> uobj;
uobj.bytes[0] = 0xff;
std::cout << uobj.obj << std::endl; 2.3 模板的虚函数问题
类模板内的成员函数模板不能声明为为虚函数,因为虚函数调用机制实现使用了一个大小固定的表,每个虚函数都对应表的一个入口,但成员函数模板在构建虚函数表之前是无法确定的。当然,类模板内的普通成员函数设置为虚函数是没问题的。
template <typename T>
class OUT_Class
{
public://virtual ~V_Class()    //OK{};template <typename T>virtual void copy(const T& obj)    //error{};
};2.4 模板的编译链接影响
目前类模板和普通类一样,是能和一个实体共享一个名称的,虽然要尽量避免这种情况。
template <typename T1, typename T2>
class A_Test
{
};int A_Test; //OK大多C++编译器都不能支持其具有C连接,因此也不建议采用extern来指定编译。并由于模板是采用外部链接的,也不能在函数内部声明模板,因为编译器无法在链接时确定到该定义。另外也不允许在模板内将模板参数再作为类名、结构名等修饰名称。
extern "C" template <typename T> class C_Test{};    //error,不支持extern "C++" template <typename T> void Func_Test(){};//可行,但多余//
void test_in(const int& obj)
{template <typename T>    //不能在函数内部声明模板class AC{};//..
};
//
template <typename T>
class AClass
{class T *inc;	//errorfriend class T; //error
};2.5 模板的模板参数
前面讲述到模板可以进行嵌套,其实,模板参数也能进行嵌套,即模板的模板参数,它的用法和类模板的用法类似:
template<typename T> class CX
{public:T val;	
};template <template<typename T> class CX> 
void func(CX<int>& obj)
{std::cout << obj.val << std::endl;
};
//
CX<int> cx_i;
cx_i.val = 20;
func(cx_i);同时模板的模板参数也支持缺省实参模板
template<typename T=int> 
class CX
{public:T val;	
};
//template <template<typename T> class CX> 	//class 替换成 struct union 是错误的
template <template<typename T> typename CX> 
//void func(CX<T> &obj)	//error,模板的模板参数的参数只能被自身其他参数的声明使用
void func(CX<int> &obj)
{std::cout << obj.val << std::endl;
};
//或者这样更好理解
template <typename T,template<typename T1> typename CX> 
void func2(CX<T> &obj)
{std::cout << obj.val << std::endl;
};
//
CX<> cx_def;
cx_def.val = 21;
func(cx_def);//
func2(cx_def);2.6 模板实参演绎事项
在篇一中,就讲述到,模板在使用时,可以显式指定模板实参,或者不指定,交给编译器去进行实参演绎,因此,最好是吧那些无法演绎的试产放在模板参数列表前面,从而显式指定这些实参,把支持实参演绎的放在后面。
template<typename T1, typename T2> 
//inline T2 im_cast(const T1& obj)    //尝试一下这样设计呢
inline T1 im_cast(const T2& obj)
{return obj;
};//
double val_ = im_cast<double>(-30);
std::cout << val_ << std::endl;2.7 模板参数是函数模板
对于模板的嵌套,还需要说明的是,函数模板可以作为函数模板的模板参数:
//函数模板嵌套
template<typename Func, typename T> 
void doSomething(Func fp,const T obj)
{fp(obj);
};template<typename T> 
void doit(const T obj)
{std::cout << obj << std::endl;
};//
doSomething(doit<int>,3);
doSomething(&doit<int>,4);
2.8 模板参数是函数指针
另外函数模板也可以作为函数指针来使用,在具体使用函数指针时,指定模板实参即可
//
template <typename T> 
void func3(const T &obj)
{std::cout << obj << std::endl;
};//
void (*pfunc3)(const int &obj);
pfunc3 = func3<int>;
pfunc3(15);
//
typedef void (*PFunc)(const float &obj);
PFunc pf = func3<float>;
pf(12.5);
(*pf)(13.5);2.9 命名空间与模板
编译器在模板调用时,会依据上下文进行名称查找,其查找是有作用域限制的,如果模板需要调用另一个命名空间namespace定义数据类型,就需要明确指出模板参数所包含的命名空间。
//
namespace pyfree{class PVal{public:int val;};std::ostream &operator<<(std::ostream &os, const PVal& obj){os << "(";os << obj.val;os <<")";return os;};
};
//
template <typename T> 
void func3(const T &obj)
{std::cout << obj << std::endl;
};
//
pyfree::PVal pval;
pval.val = 33;
func3<pyfree::PVal>(pval);总之。普通函数及类需要注意的问题,函数模板及类模板使用时一样要注意,另外由于模板的特殊性,还会延展出其很多新的问题点,当然也会对编程带来全新的编程架构和编码风格。
三、源码补充
3.1 编译
测试代码包含两个源文件template_test.h和test.cpp,通过g++ test -o test.exe编译运行测试:

3.2 源代码
template_test.h
#ifndef _TEMPLATE_TEST_H_
#define _TEMPLATE_TEST_H_#include <ostream>
#include <iostream>class DataTest
{
public:DataTest(const int &id_d,const int &id_p) : id_domain(id_d),id_point(id_p){};~DataTest(){};int id_domain;int id_point;
};
inline bool operator<(const DataTest& obj1, const DataTest& obj2) 
{ if(obj1.id_domain<obj2.id_domain)return true;if(obj1.id_domain==obj2.id_domain&&obj1.id_point<obj2.id_point)return true;return false;
};inline bool operator>(const DataTest& obj1, const DataTest& obj2) 
{ if(obj1.id_domain>obj2.id_domain)return true;if(obj1.id_domain==obj2.id_domain&&obj1.id_point>obj2.id_point)return true;return false;
};inline bool operator==(const DataTest& obj1, const DataTest& obj2) 
{ if(obj1.id_domain!=obj2.id_domain)return false;if(obj1.id_point!=obj2.id_point)return false;return true;
};inline std::ostream &operator<<(std::ostream &os, const DataTest& obj)
{os << "(";os << obj.id_domain << "," << obj.id_point;os <<")";return os;
};template <typename T1, typename T2>
class A_Test
{
public:A_Test(const T1 &id_d,const T2 &id_p) : id_domain(id_d),id_point(id_p){};~A_Test(){};T1 getDomainID() const{return id_domain;};T2 getPointID() const{return id_point;};template <typename T3, typename T4>friend std::ostream &operator<<(std::ostream &os, const A_Test<T3,T4>& obj);//template <typename T> friend bool operator>(const T& obj1, const T& obj2); //why is eroortemplate <typename T3, typename T4>friend bool operator>(const A_Test<T3,T4>& obj1, const A_Test<T3,T4>& obj2);
private:T1 id_domain;T2 id_point;
};template <typename T1, typename T2>
inline std::ostream &operator<<(std::ostream &os, const A_Test<T1,T2>& obj)
{os << "(";os << obj.id_domain << "," << obj.id_point;os <<")";return os;
};template <typename T1, typename T2>
inline bool operator<(const A_Test<T1,T2>& obj1, const A_Test<T1,T2>& obj2) 
{ if(obj1.getDomainID()<obj2.getDomainID()) return true;if(obj1.getPointID()==obj2.getPointID()&&obj1.getPointID()<obj2.getPointID()) return true;return false;
};template <typename T1, typename T2>
inline bool operator>(const A_Test<T1,T2>& obj1, const A_Test<T1,T2>& obj2) 
{ if(obj1.id_domain>obj2.id_domain) return true;if(obj1.id_domain==obj2.id_domain&&obj1.id_point>obj2.id_point) return true;return false;
};template <typename T>
inline T mymin(const T &v1, const T &v2)
{return (v1<v2)?v1:v2;
};template <typename T>
inline T mymax(const T &v1, const T &v2)
{return (v1>v2)?v1:v2;
};//
template <typename T>
class OUT_Class
{
public://virtual ~OUT_Class(){};/*template <typename T>virtual void copy(const T& obj){};*///void myfun1(const T& obj);template <typename T1>void myfun2(const T1& obj);//template <typename T1>class INT_Class1	//内部直接定义{public:T1 val;};template <typename T1>class INT_Class2;	//外部定义
};
template <typename T>
void OUT_Class<T>::myfun1(const T& obj)
{std::cout << obj << std::endl;
};template <typename T>
template <typename T1>
void OUT_Class<T>::myfun2(const T1& obj)
{std::cout << obj << std::endl;
};template <typename T>
template <typename T1>
class OUT_Class<T>::INT_Class2
{public:T1 val;	
};template <typename T>
union Chunk
{T obj;unsigned char bytes[sizeof(T)];
};//extern "C" template <typename T> class C_Test{}; //error,不支持extern "C++" template <typename T> void Func_Test(){};
/*
void test_in(const int& obj)
{template <typename T>	//不能在函数内部声明模板class AC{};//..
};
template <typename T>
class AClass
{class T *inc;	//errorfriend class T; //error
};
*/
template<typename T=int> 
class CX
{public:T val;	
};
//template <template<typename T> class CX> 	//class 替换成 struct union 是错误的
template <template<typename T> typename CX> 
//void func(CX<T> &obj)	//error,模板的模板参数的参数只能被自身其他参数的声明使用
void func(CX<int> &obj)
{std::cout << obj.val << std::endl;
};template <typename T,template<typename T1> typename CX> 
void func2(CX<T> &obj)
{std::cout << obj.val << std::endl;
};
//
template<typename T1, typename T2> 
inline T1 im_cast(const T2& obj)
{return obj;
};
//
template<typename Func, typename T> 
void doSomething(Func fp,const T obj)
{fp(obj);
};template<typename T> 
void doit(const T obj)
{std::cout << obj << std::endl;
};
//
namespace pyfree{class PVal{public:int val;};std::ostream &operator<<(std::ostream &os, const PVal& obj){os << "(";os << obj.val;os <<")";return os;};
};
//
template <typename T> 
void func3(const T &obj)
{std::cout << obj << std::endl;
};#endif
test.cpp
#include "template_test.h"
#include <string>int main(int argc, char* argv[])
{std::cout << mymin<std::string>("guangzhou","shenzhen") << std::endl;std::cout << mymax<std::string>("guangzhou","shenzhen") << std::endl;//DataTest adt(3,4),bdt(3,6);mymin<DataTest>(adt,bdt);//A_Test<int,float> a(2,4.2),b(2,3.8);std::cout << mymin<A_Test<int,float> >(a,b) << std::endl;std::cout << mymax<A_Test<int,float> >(a,b) << std::endl;//A_Test<std::string,std::string> a_s("guangzhou","huangpu"),b_s("shenzhen","baoan");if(a_s<b_s) std::cout << "a_s is min" << std::endl;if(a_s>b_s) std::cout << "a_s is max" << std::endl;//std::cout << mymin<A_Test<std::string,std::string> >(a_s,b_s) << std::endl;std::cout << mymax<A_Test<std::string,std::string> >(a_s,b_s) << std::endl;//A_Test<DataTest,DataTest> ad_s(DataTest(3,4),DataTest(4,1)),bd_s(DataTest(2,4),DataTest(3,1));std::cout << mymin<A_Test<DataTest,DataTest> >(ad_s,bd_s) << std::endl;std::cout << mymax<A_Test<DataTest,DataTest> >(ad_s,bd_s) << std::endl;//OUT_Class<int> o_a;o_a.myfun1(10);o_a.myfun2<double>(10.5);//OUT_Class<int>::INT_Class1<float> o_a_i1;o_a_i1.val = 11.4;OUT_Class<int>::INT_Class2<float> o_a_i2;o_a_i2.val = 12.4;//union Chunk<int> uobj;uobj.bytes[0] = 0xff;std::cout << uobj.obj << std::endl; //int A_Test;	//OK//CX<int> cx_i;cx_i.val = 20;func(cx_i);CX<> cx_def;cx_def.val = 21;func(cx_def);//func2(cx_i);func2(cx_def);//double val_ = im_cast<double>(-30);std::cout << val_ << std::endl;//doSomething(doit<int>,3);doSomething(&doit<int>,4);//void (*pfunc3)(const int &obj);pfunc3 = func3<int>;pfunc3(15);//typedef void (*PFunc)(const float &obj);PFunc pf = func3<float>;pf(12.5);(*pf)(13.5);//pyfree::PVal pval;pval.val = 33;func3<pyfree::PVal>(pval);return 0;
};
相关文章:
 
c/c++开发,无可避免的模板编程实践(篇二)
一、开发者需要对模板参数负责 1.1 为您模板参数提供匹配的操作 在进行模板设计时,函数模板或类模板一般只做模板参数(typename T)无关的操作为主,但是也不见得就不会关联模板参数自身的操作,尤其是在一些自定义的数据…...
 
【2023】【standard-products项目】中查找的问题与解决方案 (未完待续)
10、el-table 判断是多选操作还是单选操作 9、判断数组对象中是否包含某个指定值 需求:修改时数据回填el-select下拉数据,发现当前id在原数组里没有找到,就显示了id值,应该显示name名, 处理:当查找到id…...
 
力扣sql简单篇练习(十六)
力扣sql简单篇练习(十六) 1 产品销售分析|| 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 SELECT p.product_id,sum(s.quantity) total_quantity FROM Product p INNER JOIN Sales s ON p.product_ids.product_id GROUP BY p.product_id1.3 运行截…...
青少年蓝桥杯python组(STEMA中级组)
第一套编程题第一题【编程实现】输入一个字符串(N),输出该字符串的长度。输入描述:输入一个字符串 N输出描述:输出该字符串的长度【样例输入】abcd【样例输出】4N input() print(len(N))第二题【提示信息】小蓝家的灯…...
 
JVM内存结构,Java内存模型,Java对象模型
一.整体方向JVM内存结构是和java虚拟机的运行时区域有关。Java内存模型和java并发编程有关。java对象模型和java对象在虚拟机中的表现形式有关。1.JVM内存结构堆:通过new或者其他指令创建的实例对象,会被垃圾回收。动态分配。虚拟机栈:基本数…...
 
跨境电商新形式下,如何选择市场?
2022年,全球经济已经有增长乏力、通胀高起的趋势,美国等国家的通货膨胀情况令人担忧,不少行业面临更为复杂的外部环境以及严峻的市场挑战。不过,跨境电商行业依旧保持着较高的增长速度,越来越多有远见的卖家将电商事业…...
 
MySQL的触发器
目录 一.概述 介绍 触发器的特性 操作—创建触发器 操作—new和old 操作—查看触发器 操作—删除触发器 注意事项 一.概述 介绍 触发器,就是一种特殊的存储过程。触发器和存储过程一样是一个能够完成特定功能、存储在数据库服务器上的SQL片段,但是…...
内存映射模块读写文件提高IO性能mmap
内存映射模块读写文件提高IO性能mmap 1.概述 这篇文章介绍下与普通读写文件不同的方式,内存映射读写文件。在什么情况下才会用到内存映射操作文件那,还是要先了解下他。 1.1.内存映射与IO区别 常规操作IO开销 常规的操作文件是经过下面几个环节操作I…...
 
存储硬件与协议
存储硬件与协议存储设备的历史轨迹存储介质的进化3D NAND3D XPointIntel Optane存储接口协议的演变NVMeNVMe-oF网络存储技术1)DAS2)NAS3)SAN4)iSCSIiSCSI层次结构存储设备的历史轨迹 1.穿孔卡2.磁带3.硬盘4.磁盘(软盘…...
智能物流半导体发展
智能物流半导体在国内的发展,国内巨大的人口基数,这将会不断促进智慧物流的发展。智能物流在未来发展的潜力巨大。 关于触屏的设计是界面越简单,越清晰越好,最近设计一个小车控制触屏软件。把小车当前所在信息通过图像显示出来。…...
 
SAP S/4HANA 概述
智能企业业务技术平台Business Technology Platform提供数据管理和分析,并支持应用程序开发和集成。它还允许我们的客户使用人工智能、机器学习和物联网等智能技术来推动创新。业务网络Business network帮助客户实现跨公司业务流程的数字化。该网络建立在我们的采购…...
太上感应篇
太上感应篇原文 太上曰。祸福无门。惟人自召。善恶之报。如影随形。 是以天地有司过之神。依人所犯轻重。以夺人算。算减则贫耗。多逢忧患。人皆恶之。刑祸随之。吉庆避之。恶星灾之。算尽则死。 又有三台北斗神君。在人头上。录人罪恶。夺其纪算。又有三尸神。在人身中。每…...
 
FPGA入门系列17--task
文章简介 本系列文章主要针对FPGA初学者编写,包括FPGA的模块书写、基础语法、状态机、RAM、UART、SPI、VGA、以及功能验证等。将每一个知识点作为一个章节进行讲解,旨在更快速的提升初学者在FPGA开发方面的能力,每一个章节中都有针对性的代码…...
 
React学习笔记(番外二)——列表多选批量处理复合组件
React学习笔记(番外二)——列表多选批量操作复合组件前言〇、Show you the code一、 任务分析及拆解表头行的Checkbox——总开关记录行的Checkbox——行级开关二、 基础实现表头行的文件——header-row.js记录行的文件——record-row.js页面的文件App.js…...
 
Pom.xml详解
目录 1、Maven的下载安装 2、什么是pom? 3、较完整的pom元素 4、默认生成Maven工程的pom内容 5、自定义的属性变量 6、依赖管理 6.1、整体依赖关系列表 6.2、依赖关系的传递性 6.3、依赖传递可能造成的问题 6.3.1、scope依赖范围 6.3.2、依赖调节 6.3.3…...
 
浅谈软件测试需求管理
什么是需求管理? 需求管理,指对产品、系统或工程的开发需求的搜集、定义、分析、评审、整理、维护、追溯和复用等相关的管理工作和流程。通常特指应用程序或软件系统的研发需求。需求管理和配置管理、测试管理、缺陷管理、风险管理、变更管理等管理流程…...
面试题复盘
Vuex与本地存储的区别Vuex是一个专门为Vue.js应用程序开发的状态管理模式和库。它提供了一个中央存储库,用于存储应用程序的所有组件之间共享的状态【组件间通信的一种方法,一般用于中大型应用】。Vuex的主要目的是在Vue.js应用程序中管理复杂的状态逻辑…...
 
Telerik UI for WPF 2023 R1
Telerik UI for WPF 2023 R1 之 WPF 的 Telerik 用户界面,WPF 控件库开发人员信任,快速构建美观、高性能的 WPF 业务应用程序。现在支持 .NET 6 和 7.0。 概述部分背景图像 主要特征 现代专业主题图标,现代专业主题 通过各种受 Office、Wind…...
 
基于 CentOS7 的 KVM 部署 + 虚拟机创建
目录一、实验环境二、部署 KVM三、创建虚拟机四、远程管理 KVM 虚拟机FAQ一、实验环境 实验环境:VMware Workstation 16 Pro 打开虚拟机之前,首先开启 VMware Workstation Pro 16 上的硬件辅助虚拟化功能,如下图所示: 二、部署 …...
 
Python自动化测试实战篇(5)优化selenium+unittest+ddt,搞定100条测试用例只执行前50条
这些是之前的文章,里面有一些基础的知识点在前面由于前面已经有写过,所以这一篇就不再详细对之前的内容进行描述 Python自动化测试实战篇(1)读取xlsx中账户密码,unittest框架实现通过requests接口post登录网站请求&…...
 
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
 
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
 
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
 
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
 
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
 
中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
