当前位置: 首页 > news >正文

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<' success

        1.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; //OK

        1.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 为您模板参数提供匹配的操作 在进行模板设计时&#xff0c;函数模板或类模板一般只做模板参数&#xff08;typename T&#xff09;无关的操作为主&#xff0c;但是也不见得就不会关联模板参数自身的操作&#xff0c;尤其是在一些自定义的数据…...

【2023】【standard-products项目】中查找的问题与解决方案 (未完待续)

10、el-table 判断是多选操作还是单选操作 9、判断数组对象中是否包含某个指定值 需求&#xff1a;修改时数据回填el-select下拉数据&#xff0c;发现当前id在原数组里没有找到&#xff0c;就显示了id值&#xff0c;应该显示name名&#xff0c; 处理&#xff1a;当查找到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中级组)

第一套编程题第一题【编程实现】输入一个字符串&#xff08;N&#xff09;&#xff0c;输出该字符串的长度。输入描述&#xff1a;输入一个字符串 N输出描述&#xff1a;输出该字符串的长度【样例输入】abcd【样例输出】4N input() print(len(N))第二题【提示信息】小蓝家的灯…...

JVM内存结构,Java内存模型,Java对象模型

一.整体方向JVM内存结构是和java虚拟机的运行时区域有关。Java内存模型和java并发编程有关。java对象模型和java对象在虚拟机中的表现形式有关。1.JVM内存结构堆&#xff1a;通过new或者其他指令创建的实例对象&#xff0c;会被垃圾回收。动态分配。虚拟机栈&#xff1a;基本数…...

跨境电商新形式下,如何选择市场?

2022年&#xff0c;全球经济已经有增长乏力、通胀高起的趋势&#xff0c;美国等国家的通货膨胀情况令人担忧&#xff0c;不少行业面临更为复杂的外部环境以及严峻的市场挑战。不过&#xff0c;跨境电商行业依旧保持着较高的增长速度&#xff0c;越来越多有远见的卖家将电商事业…...

MySQL的触发器

目录 一.概述 介绍 触发器的特性 操作—创建触发器 操作—new和old 操作—查看触发器 操作—删除触发器 注意事项 一.概述 介绍 触发器&#xff0c;就是一种特殊的存储过程。触发器和存储过程一样是一个能够完成特定功能、存储在数据库服务器上的SQL片段&#xff0c;但是…...

内存映射模块读写文件提高IO性能mmap

内存映射模块读写文件提高IO性能mmap 1.概述 这篇文章介绍下与普通读写文件不同的方式&#xff0c;内存映射读写文件。在什么情况下才会用到内存映射操作文件那&#xff0c;还是要先了解下他。 1.1.内存映射与IO区别 常规操作IO开销 常规的操作文件是经过下面几个环节操作I…...

存储硬件与协议

存储硬件与协议存储设备的历史轨迹存储介质的进化3D NAND3D XPointIntel Optane存储接口协议的演变NVMeNVMe-oF网络存储技术1&#xff09;DAS2&#xff09;NAS3&#xff09;SAN4&#xff09;iSCSIiSCSI层次结构存储设备的历史轨迹 1.穿孔卡2.磁带3.硬盘4.磁盘&#xff08;软盘…...

智能物流半导体发展

智能物流半导体在国内的发展&#xff0c;国内巨大的人口基数&#xff0c;这将会不断促进智慧物流的发展。智能物流在未来发展的潜力巨大。 关于触屏的设计是界面越简单&#xff0c;越清晰越好&#xff0c;最近设计一个小车控制触屏软件。把小车当前所在信息通过图像显示出来。…...

SAP S/4HANA 概述

智能企业业务技术平台Business Technology Platform提供数据管理和分析&#xff0c;并支持应用程序开发和集成。它还允许我们的客户使用人工智能、机器学习和物联网等智能技术来推动创新。业务网络Business network帮助客户实现跨公司业务流程的数字化。该网络建立在我们的采购…...

太上感应篇

太上感应篇原文 太上曰。祸福无门。惟人自召。善恶之报。如影随形。 是以天地有司过之神。依人所犯轻重。以夺人算。算减则贫耗。多逢忧患。人皆恶之。刑祸随之。吉庆避之。恶星灾之。算尽则死。 又有三台北斗神君。在人头上。录人罪恶。夺其纪算。又有三尸神。在人身中。每…...

FPGA入门系列17--task

文章简介 本系列文章主要针对FPGA初学者编写&#xff0c;包括FPGA的模块书写、基础语法、状态机、RAM、UART、SPI、VGA、以及功能验证等。将每一个知识点作为一个章节进行讲解&#xff0c;旨在更快速的提升初学者在FPGA开发方面的能力&#xff0c;每一个章节中都有针对性的代码…...

React学习笔记(番外二)——列表多选批量处理复合组件

React学习笔记&#xff08;番外二&#xff09;——列表多选批量操作复合组件前言〇、Show you the code一、 任务分析及拆解表头行的Checkbox——总开关记录行的Checkbox——行级开关二、 基础实现表头行的文件——header-row.js记录行的文件——record-row.js页面的文件App.js…...

Pom.xml详解

目录 1、Maven的下载安装 2、什么是pom&#xff1f; 3、较完整的pom元素 4、默认生成Maven工程的pom内容 5、自定义的属性变量 6、依赖管理 6.1、整体依赖关系列表 6.2、依赖关系的传递性 6.3、依赖传递可能造成的问题 6.3.1、scope依赖范围 6.3.2、依赖调节 6.3.3…...

浅谈软件测试需求管理

什么是需求管理&#xff1f; 需求管理&#xff0c;指对产品、系统或工程的开发需求的搜集、定义、分析、评审、整理、维护、追溯和复用等相关的管理工作和流程。通常特指应用程序或软件系统的研发需求。需求管理和配置管理、测试管理、缺陷管理、风险管理、变更管理等管理流程…...

面试题复盘

Vuex与本地存储的区别Vuex是一个专门为Vue.js应用程序开发的状态管理模式和库。它提供了一个中央存储库&#xff0c;用于存储应用程序的所有组件之间共享的状态【组件间通信的一种方法&#xff0c;一般用于中大型应用】。Vuex的主要目的是在Vue.js应用程序中管理复杂的状态逻辑…...

Telerik UI for WPF 2023 R1

Telerik UI for WPF 2023 R1 之 WPF 的 Telerik 用户界面&#xff0c;WPF 控件库开发人员信任&#xff0c;快速构建美观、高性能的 WPF 业务应用程序。现在支持 .NET 6 和 7.0。 概述部分背景图像 主要特征 现代专业主题图标&#xff0c;现代专业主题 通过各种受 Office、Wind…...

基于 CentOS7 的 KVM 部署 + 虚拟机创建

目录一、实验环境二、部署 KVM三、创建虚拟机四、远程管理 KVM 虚拟机FAQ一、实验环境 实验环境&#xff1a;VMware Workstation 16 Pro 打开虚拟机之前&#xff0c;首先开启 VMware Workstation Pro 16 上的硬件辅助虚拟化功能&#xff0c;如下图所示&#xff1a; 二、部署 …...

Python自动化测试实战篇(5)优化selenium+unittest+ddt,搞定100条测试用例只执行前50条

这些是之前的文章&#xff0c;里面有一些基础的知识点在前面由于前面已经有写过&#xff0c;所以这一篇就不再详细对之前的内容进行描述 Python自动化测试实战篇&#xff08;1&#xff09;读取xlsx中账户密码&#xff0c;unittest框架实现通过requests接口post登录网站请求&…...

C语言--数据的存储2

目录前言练习有符号类型与无符号类型char类型的取值范围有符号char无符号char有符号与无符号类型混合运算有符号无符号类型形成的bugchar类型取值范围应用浮点型在内存中的存储浮点数的存储浮点数存储规则浮点数取出规则前言 上篇文章我们讲解了数据类型&#xff0c;类型的基本…...

Ubuntu 安装 Qt5.7.0

下载 地址&#xff1a;https://download.qt.io/https://download.qt.io/ 文件夹说明&#xff1a; snapshots&#xff1a;预览版&#xff0c;该文件夹中包含最新的测试版本。 online&#xff1a;在线安装包。 official_releases&#xff1a;最终发布版。 new_archive&#…...

“世界”的伊利,“三难”的潘刚

&#xff08;图片来源于网络&#xff0c;侵删&#xff09; 来源 | 螳螂观察 文 | 叶小安 一棵草&#xff0c;一头牛&#xff0c;到一杯牛奶&#xff0c;乳品如何守住舌尖上的安全&#xff1f; 央视财经频道专访中&#xff0c;伊利集团董事长兼总裁潘自信满满地介绍了现代智…...

【新】华为OD机试 - 开心消消乐(Python)

开心消消乐 题目 给定一个 N 行 M 列的二维矩阵,矩阵中每个位置的数字取值为 0 或 1,矩阵示例如: 1 1 0 0 0 0 0 1 0 0 1 1 1 1 1 1现需要将矩阵中所有的 1 进行反转为 0,规则如下: 当点击一个 1 时,该 1 被反转为 0,同时相邻的上、下、左、右,以及左上、左下、右上…...

山东大学2022-2023数据仓库挖掘期末考题回忆

2023.2.14 一、 1.数据预处理的过程和解决问题 2.什么是离群点&#xff0c;检测离群点的四个方法 3.数据仓库的四个特点&#xff0c;画出数据仓库结构图 4.维度归约的两个方法及区别。 二、 两个模型用来预测新冠病毒的阳性和阴性 1.分别求准确率&#xff0c;精确率&#xff0c…...

SSM整合

SSM整合 ContextLoaderListener Spring提供了监听器ContextLoaderListener&#xff0c;实现ServletContextListener接口&#xff0c;可监听 ServletContext的状态&#xff0c;在web服务器的启动&#xff0c;读取Spring的配置文件&#xff0c;创建Spring的IOC容器。 web 应用中…...

Android平台版本所对应的 API 级别

平台版本API级别版本号备注Android 1333TIRAMISU平台亮点Android 1232S_V2平台亮点31S平台亮点Android 1130R平台亮点Android 1029Q平台亮点Android 928P平台亮点Android 8.127O_MR1平台亮点Android 8.026O平台亮点Android 7.1.1Android 7.125N_MR1平台亮点Android 7.024N平台亮…...

入职字节外包一个月,我离职了

有一种打工人的羡慕&#xff0c;叫做“大厂”。 真是年少不知大厂香&#xff0c;错把青春插稻秧。 但是&#xff0c;在深圳有一群比大厂员工更庞大的群体&#xff0c;他们顶着大厂的“名”&#xff0c;做着大厂的工作&#xff0c;还可以享受大厂的伙食&#xff0c;却没有大厂…...

中创教育PMP分享,复盘没效果?该怎么办

复盘的清单框架 一、现在情况如何 二、当初是怎么决定的 三、让我们再审视下思考的前提 四、复盘他人 复盘没效果&#xff0c;我们可以试试下面的提问&#xff1a; 一、现在情况如何 现在做到什么程度? 当时定的目标是多少? 现在的结果和目标对比处于什么状态? 有没…...

Kubelet监控指标说明

Probe路径 含义&#xff1a;kubelet以及kubelet监控的Pod的存活性请求路径&#xff1a;“/metrics/probes”指标 名称类型含义upGauge服务是否存活prober_probe_totalCounter按结果计算容器的活动探测、就绪探测或启动探测的累计数目以及存活性结果 Metrics路径 含义&#x…...