c++可调用对象、function类模板与std::bind
函数调用与函数调用运算符
先写一个简单的函数,如下:
/*函数的定义*/
int func(int i)
{cout<<"这是一个函数\t"<<i<<endl;
}void test()
{func(1);//函数的调用
}
通过这个普通的函数可以看到,调用一个函数很简单,首先是函数名,后面跟一对圆括号,如果这个函数有参数,就在函数调用位置的函数名后圆括号中给出实参,在函数定义位置函数名后圆括号中给出形参
函数调用总离不开一对圆括号,这个“()”就叫函数调用运算符
特别的,如果在类中重载了这个函数调用运算符(),我们就可以像使用函数一样使用类的对象,换句话说就可以像函数调用一样来“调用”该类的对象。
这种重载了()的类对象,就叫做函数对象,如下
class biggerThanZero
{
public:int m_i;biggerThanZero(int i):m_i(i){cout<<"构造函数调用了"<<endl;}int operator()(int num){if(num<0) return 0;return num;}
};void test()
{biggerThanZero bz1(10);//这是对象定义的初始化,会调用类的构造函数int num=-20;cout<<bz1(num)<<endl;//这才是调用了类的函数调用运算符()}

分析代码并观察运行结果可以看到,测试函数中的第一行代码是一个正常的调用构造函数对类对象进行初始化的代码,而接下来的两行代码里的bz1(num)才是对函数调用运算符的调用,观察其书写形式可以发现,其调用形式与文章开头的普通函数func调用形式是相同的。
这就是可调用对象,即
- func函数
- 重载了函数调用运算符“()”的biggerthanzero类所生成的对象bz1,我们调用bz1时可以像调用函数那样进行调用
问题的引出
继续观察这两个可调用对象,可以发现他们的调用形式都是相同的,也就是int (int),同时这也是func的函数类型
注:函数类型就是返回值类型和参数类型的组合。
如func函数中的参数类型是int,而返回值类型int,因此func的函数类型就是int (int)。
同理,假如现在有一个函数的声明为 void fun(double);则这个fun函数的函数类型就是
void (double)
而我们又知道,我们可以使用一个函数指针来保存函数地址,那么操作这个函数指针就等同于操作这个函数指针所指向的函数,如下所示
void test()
{int (*fp)(int);//定义一个函数指针,也就是可以保存函数地址的指针fp=func;//在c++中,函数名就是这个函数的地址,也可以使用fp=&funcfp(1);//由于fp现在指向func,因此调用fp(1)就等同于调用func(1)
}
但是对于相同的调用形式的函数对象,我们却不能使用函数指针进行统一调用
void test()
{int (*fp)(int,int);biggerThanZero bz(0);//类对象初始化fp=bz;//报错
}

这说明系统并没有把类biggerthanzero的对象bz看成一个函数指针,当然系统更不可能把类biggerthanzero看成一个函数指针
那么问题来了,对于具有相同调用形式的不同可调用对象,是否可以使用一个统一的调用呢?
function类模板的引出
暂时先搁置一下上边提到的概念,我们暂时已经知道以下三点:
- 普通函数和重载了函数调用运算符()的对象都是可调用对象
- 可以使用函数指针统一调用普通函数这个可调用对象
- 但是同为可调用对象的函数对象却无法使用函数指针进行统一调用
接下来,我们做两个实验来引出function类模板
观察以下代码
int max(int a,int b)
{return (a>b)?a:b;
}int min(int a,int b)
{return (a<b)?a:b;
}void test()
{cout<<max(1,2)<<endl;cout<<min(1,2)<<endl;
}
在这段代码里,我们定义了两个函数,分别是max函数和min函数,并且我们在测试函数中调用了他们。
实验一
仔细观察这段代码,可以发现max函数和min函数的函数类型是相同的,都是int(int ,int ),因此我们可以使用一个函数指针来对他们进行统一形式的调用,如下
void test()
{int (*fp)(int,int);//定义一个函数指针fp=max;//将max函数的函数地址赋给函数指针fpcout<<fp(1,2)<<endl;//现在fp指向的是max函数,调用fp(1,2)等同于调用max(1,2)fp=min;//将min函数的函数地址赋给函数指针fpcout<<fp(1,2)<<endl;//现在fp指向的是min函数,调用fp(1,2)等同于调用min(1,2)
}
运行结果如下:

其实,这就是函数指针最开始的作用,但是后来面向对象诞生之后这种写法就被替代了。
实验二
再进一步,我们可以使用一个map来对这段逻辑进行重写,如下:
void test()
{map<string,int(*)(int,int)> mp;mp.insert({"max",max});mp.insert({"min",min});cout<<mp["max"](1,2)<<endl;//等同于调用max(1,2)cout<<mp["min"](1,2)<<endl;//等同于调用min(1,2)
}

在上述代码里,我们使用一个map对上述调用形式进行了统一的改写,map键值对的键类型是string,而值类型是函数类型为int(int,int)的函数指针
综上观察,我们可以说
- 同为可调用对象,且函数对象和普通函数的调用形式是相同的,但是我们只能使用函数指针对调用形式相同(函数类型名相同)的普通函数进行统一调用
- 但是我们却无法再进一步对相同调用形式的函数对象进行统一调用
为了解决以上问题,c++引入了function模板的概念,我们直接看代码
int func(int i)
{cout<<"这是一个函数\t"<<i<<endl;
}class biggerThanZero
{
public:int m_i;biggerThanZero(int i):m_i(i){cout<<"构造函数调用了"<<endl;}int operator()(const int& num){if(num<0) return 0;return num;}
};void test()
{function<int(int)> fp2;fp2=func;cout<<fp2(10)<<endl;biggerThanZero bz(0);fp2=bz;cout<<fp2(-1)<<endl;
}

现在我们可以拿出function类模板的定义和作用了
function的类模板,就是用来包装一个可调用对象的,换句话说,它可以像函数指针那样,将不同的可调用对象包装成一个相同的东西,以方便我们使用
正如我们使用函数指针那样,对于同一个函数指针,我们可以赋给它不同的函数地址,只要这些函数的调用形式是相同的,我们就可以使用这一个指针实现不同的函数调用,而function类模板实现的就是类似的功能
现在,我们就可以进一步使用map来对可调用对象进行统一封装了
void test()
{biggerThanZero bz(0);map<string,function<int(int)>> mp={{"func",func},{"biggerThanZero",bz}};mp["func"](20);cout<<mp["biggerThanZero"](-10)<<endl;
}

因此,我们可以把函数、可调用对象等都包装成function<int(int)>对象。
但是,值得说明的是,无法对重载的函数包装进function中
我们只能这样写
void test() {function<int(int,int)> fc;int(*fp)(int,int)=max;fc=fp;cout<<fc(1,2)<<endl;}
可调用对象
在上边我们已经说了有关可调用对象的概念,这里再强调一下,普通函数和重载了函数调用运算符的类对象(也就是函数对象)都是可调用对象,他们都可以像使用普通函数调用那样进行调用
除了上述两个可调用对象外,其余还有一些可调用对象,我们一并进行介绍
1.函数指针
普通函数的函数名就是一个函数地址,是一个可调用对象,我们已经介绍过了
void func()
{cout<<"func运行了"<<endl;
}void test()
{void(*fp)()=func;//定义函数指针,并使用func的函数地址进行初始化fp();//调用函数,这是一个可调用对象
}
2.函数对象(仿函数)
具有operator()成员函数的类对象也是一个可调用对象,我们也已经介绍过了。在这里我们给出函数对象(仿函数)的定义
仿函数的定义:仿函数(functors)又称为函数对象(function objects),是一个能行使函数功能的类所定义的对象。仿函数的语法几乎和普通的函数调用一样
class TC
{
public:void operator()(int tv){cout<<"TC::operator()执行了\t"<<tv<<endl;}
};void test()
{TC tc;tc(10);//像调用函数那样调用()操作符,等价于tc.operator(10)
}
3.可转换为函数指针的类对象
其实,函数指针都是可调用对象,可以在代码中像函数一样使用。
这在我们之前探讨函数指针的时候已经见到过了,当时我们定义了两个函数类型为int(int,int)的max函数与min函数,并使用同一个函数指针分别指向max函数和min函数的地址进行调用,使用函数指针进行调用的时候我们也观察到其调用与普通函数调用无异
现在我们说一种特殊的函数指针,如下
可转换为函数指针的类对象也叫做函数对象或者仿函数
在说这个问题之前,先说一下有关类型转换的问题
我们知道
- 一个类对象的类型就是定义这个对象的类本身,比如上边的对象tc的类型就是TC。
- 常用的普通类型之间是可以进行类型转换的,如int可以转换成double,而double可以转换成int
- 再进一步,我们又知道,我们可以将一个int类型的变量转换为一个类类型,只要这个类提供了对应的构造函数,如下:
class TS { public:int m_i;TS(){cout<<"无参构造函数调用了"<<endl;};TS(int a):m_i(a){cout<<"带参数的构造函数调用了"<<endl;} };void test() {TS ts;ts=10;//通过构造一个临时对象,将int类型的10转换为一个TS类型的变量 }
当然,上述这种类型转换是隐式,而如果我们不希望编译器为我们使用这种int到类型之间的隐式类型转换,使用显示类型转换也是可以的,如下:
class TS { public:int m_i;TS(){cout<<"无参构造函数调用了"<<endl;};explicit TS(int a):m_i(a)//声明explicit,不允许编译器使用隐式类型转换{cout<<"带参数的构造函数调用了"<<endl;} };void test() {TS ts;//由于构造函数使用了explicit关键字,不允许编译器使用隐式类型转换,因此我们只能使用显示类型转换ts=TS(10); }
那么问题来了,是否可以将一个类类型转换为一个普通类型呢,如将上述的TS类类型转换成一个int类型?
答案当然也是肯定的。
类型转换运算符
类型转换运算符,也叫做类型转换函数,是类的一种特殊成员函数,它能将一个类类型对象转成某个其他类型数据
其一般形式为:

先说以下几点说明,我们再使用代码进行实验
- 末尾的const是可选项,表示不应该改变待转换对象的内容,但不是必须有const
- “类型名”表示要转换成的某种类型,一般只要是能作为函数返回类型的类型都可以。所以一般不可以转成数组类型或者函数类型(把一个函数声明去掉函数名剩余的部分就是函数类型,如void(inta,intb)),但是转换成数组指针、函数指针、引用等都是可以的。
- 类型转换运算符,没有形参(形参列表必须为空),因为类型转换运算符是隐式执行的,所以无法给这些函数传递参数。同时,也不能指定返回类型,但是却会返回一个对应类型(“类型名”所指定的类型)的值。
- 必须定义为类的成员函数
接下来,我们做实验以做验证
class TS
{
public:int m_i;TS(){cout<<"无参构造函数调用了"<<endl;};TS(int a):m_i(a)//声明explicit,不允许编译器使用隐式类型转换{cout<<"带参数的构造函数调用了"<<endl;}//类型转换运算符,必须定义为一个成员函数//表示编译器可以调用这个函数隐式的将TS类型的变量转换为一个int类型的变量operator int() const{return m_i;}
};void test()
{TS ts1;//普通构造ts1=10;//调用带参构造,将int类型的10隐式转换为TS类型的变量int res=ts1+20;//隐式调用operator int()成员函数将对象ts1转换为int类型变量之后再做加法运算cout<<res<<endl;int res2=ts1.operator int()+30;//也可以显示的调用operator int()成员函数将对象ts1转换为int类型变量cout<<res2<<endl;
}

上述代码执行过程为
- 调用无参构造函数构造ts1对象
- 调用有参构造函数并生成一个临时对象,隐式的将int类型变量的10转换为一个TS类型变量,再把这个临时对象赋给ts1
- 隐式的调用operator int()成员函数将ts1转换为int类型,再进行加法运算,执行10+20
- 显示的调用operator int()成员函数将ts1转换为int类型,再进行加法运算,执行10+30
同样的,如果我们想拒绝隐式类型转换,也可以使用显示类型转换运算,如下:
class TS
{
public:int m_i;TS(){cout<<"无参构造函数调用了"<<endl;};TS(int a):m_i(a)//声明explicit,不允许编译器使用隐式类型转换{cout<<"带参数的构造函数调用了"<<endl;}//类型转换运算符,必须定义为一个成员函数//表示编译器可以调用这个函数隐式的将TS类型的变量转换为一个int类型的变量explicit operator int() const//拒绝编译器使用隐式类型转换{return m_i;}
};void test()
{TS ts1;//普通构造ts1=10;//调用带参构造,将int类型的10隐式转换为TS类型的变量int res=static_cast<int>(ts1)+20;//显示类型转换cout<<res<<endl;
}

现在我们转回正题,我们现在已经知道了,类类型也可以转换为其他类型,如int类型,而类类型也同样可以转换为函数指针类型,而这种可以转换为函数指针的类对象,也是一种可调用对象
为了说明问题,我们继续写一个测试代码
class TS
{
public:int m_i;TS(){cout<<"无参构造函数调用了"<<endl;};TS(int a):m_i(a)//声明explicit,不允许编译器使用隐式类型转换{cout<<"带参数的构造函数调用了"<<endl;}static void myfunc(int v1){cout<<"static myfunc函数执行了\t"<<v1<<endl;}//类型定义,void(*)(int)是一个函数指针类型,使用tfpoint替换这个类型//等价于typedef void(*tfpoint)(int)using tfpoint=void(*)(int);operator tfpoint(){cout<<"类型转换运算符调用了"<<endl;return myfunc;}
};void test()
{TS ts;//执行operator tfpoint(),之后再执行myfunc(123)ts(123);
}

4.lambda表达式
lambda表达式也是一种可调用对象,参见
lambda表达式c++-CSDN博客
可调用对象总结
其实,可调用对象首先被看作一个对象,程序员可以对其使用函数调用运算符“()”,那就可以称其为“可调用的”
function类模板
如果找通用性,上述提到的这几种可调用对象的调用形式都比较统一,那么,有没有什么方法能够把这些可调用对象的调用形式统一一下呢?有,那就是使用std::function把这些可调用对象包装起来。这在我们之前也已经实验过了
但有一点需要注意,function类模板用来往里装各种可调用对象,但是它不能装类成员函数指针,因为类成员函数指针是需要类对象参与才能完成调用的。
std::function类模板的特点是:通过指定模板参数,它能够用统一的方式来处理各种可调用对象。
1.绑定普通函数
void func1(int num)
{cout<<"这是一个普通函数func1:"<<num<<endl;
}void test()
{function<void(int)> fp1=func1;//绑定一个普通函数func1(10);
}
2.绑定类的静态成员函数
class TC
{
public:static void stcfunc(int num){cout<<"TC类的静态成员函数执行了:"<<num<<endl;}
};void test()
{function<void(int)> fp2=TC::stcfunc;fp2(20);
}
3.绑定仿函数
class TC
{
public:int m_i;TC(int i=0):m_i(i){cout<<"构造函数运行了"<<endl;}void operator()(int num){cout<<"函数调用运算符运行了:"<<num<<endl;}static void stcfunc(int num){cout<<"TC类的静态成员函数执行了:"<<num<<endl;}
};void test()
{
// function<void(int)> fp1=func1;//绑定一个普通函数
// func1(10);function<void(int)> fp2=TC::stcfunc;fp2(20);TC tc;function<void(int)> fp3=tc;//TC类声明了函数调用运算符,因此对象tc是一个函数对象fp3(30);
}
std::bind绑定器
std::bind能将对象以及相关的参数绑定到一起,绑定完后可以直接调用,也可以用std::function进行保存,在需要的时候调用。
std::bind有两个意思:·
- 将可调用对象和参数绑定到一起,构成一个仿函数,所以可以直接调用。·
- 如果函数有多个参数,可以绑定部分参数,其他的参数在调用的时候指定。
绑定普通函数
#include<iostream>
#include<functional>
using namespace std;void func1(int x,int y,int z)
{cout<<"x="<<x<<",y="<<",z="<<z<<endl;
}void test()
{function<void(int,int,int)> bf1=bind(func1,10,20,30);bf1(10,20,30);auto bf2=bind(func1,10,20,30);bf2();}int main()
{test();// system("pause");return 0;
}
参数占位符
#include<iostream>
#include<functional>
using namespace std;
using namespace placeholders;void func1(int x,int y,int z)
{cout<<"x="<<x<<",y="<<y<<",z="<<z<<endl;
}void test()
{//_1和_2分别表示func1的第一个参数和第二个参数暂时不定,需要自己传入auto bf2=bind(func1,_1,_2,30);bf2(10,20);auto bf3=bind(func1,_2,_1,30);bf3(10,20);
}int main()
{test();// system("pause");return 0;
}

可以看到,分别调整参数占位符的位置后,输出的结果是不一样的
绑定函数对象
class CQ
{
public:void operator()(int x,int y){cout<<x<<"\t"<<y<<endl;}
};void test()
{CQ cq;bind(cq,10,20)();bind(cq,_1,20)(5);
}
绑定类成员函数
#include<iostream>
#include<functional>
using namespace std;
using namespace placeholders;void func1(int x,int y,int z)
{cout<<"x="<<x<<",y="<<y<<",z="<<z<<endl;
}class CQ
{
public:int m_a=0;void operator()(int x,int y){cout<<x<<"\t"<<y<<endl;}void classFunc(int num){cout<<"this is a class func:"<<num<<endl;m_a=num;}
};void test()
{CQ cq;// bind(cq,10,20)();// bind(cq,_1,20)(5);bind(&CQ::classFunc,cq,55)();cout<<"m_a="<<cq.m_a<<endl;bind(&CQ::classFunc,&cq,_1)(23);cout<<"m_a="<<cq.m_a<<endl;}int main()
{test();// system("pause");return 0;
}

注意,上面的代码中
第一个std::bind的调用中,第二个参数cq会导致生成一个临时的CQ对象,std::bind是将该临时对象和相关的成员函数以及多个参数绑定到一起,后续对myfunpt成员函数的调用修改的是这个临时的CQ对象的m_a值,并不影响真实的cq对象的m_a值。
如果将std::bind的第二个参数cq前增加&,这样就不会导致生成一个临时的CQ对象,后续的myfunpt调用修改的就会是cq对象的m_a值。
这就是为什么第二个std::bind模板调用后m_a的值改变的原因
绑定类成员变量
#include<iostream>
#include<functional>
using namespace std;
using namespace placeholders;void func1(int x,int y,int z)
{cout<<"x="<<x<<",y="<<y<<",z="<<z<<endl;
}class CQ
{
public:int m_a;CQ(int num=0):m_a(num){cout<<"构造函数调用了"<<endl;}CQ(const CQ& cq):m_a(cq.m_a){cout<<"拷贝构造函数调用了"<<endl;}void operator()(int x,int y){cout<<x<<"\t"<<y<<endl;}void classFunc(int num){cout<<"this is a class func:"<<num<<endl;m_a=num;}virtual ~CQ(){cout<<"析构函数执行了"<<endl;}};void test()
{CQ cq;function<int&(void)> fp=bind(&CQ::m_a,cq);fp()=66;cout<<cq.m_a<<endl;
}int main()
{test();// system("pause");return 0;
}
注意观察输出

把成员变量地址当函数一样绑定,绑定的结果放在std::function<int &(void)>里保存。换句话说,就是用一个可调用对象的方式来表示这个变量,bind这个能力还是比较神奇的。
重点分析一下代码行“bf7()=60;”,因为其上面的那行代码用了&cq,所以这里等价于cq.m_a=60。如果cq前不用&,发现会调用两次CQ类的拷贝构造函数。
为什么调用两次拷贝构造函数呢?
第一次是因为第一个参数为cq,所以利用cq产生一个临时的CQ对象
第二次是因为std::bind要返回一个CQ对象(确切地说是经过std::bind包装起来的CQ对象),所以要返回的这个CQ对象(仿函数)复制自这个临时CQ对象,但bind这行执行完毕后,临时CQ对象被释放,返回的这个CQ对象(仿函数)放到了bf7里。
所以上述std::bind代码行中,一般都应该用&cq,否则最终会多调用两次拷贝构造函数和两次析构函数,用了&cq后这4次调用全省了,提高了程序运行效率。
void test()
{CQ cq;function<int&(void)> fp=bind(&CQ::m_a,&cq);fp()=66;cout<<cq.m_a<<endl;
}

总结
- 因为有了占位符(placeholder)这种概念,所以std::bind的使用就变得非常灵活。可以直接绑定函数的所有参数,也可以仅绑定部分参数。绑定部分参数时,就需要通过std::placeholders来决定bind所在位置的参数将会属于调用发生时的第几个参数。
- std::bind的思想实际上是一种延迟计算的思想,将可调用对象保存起来,然后在需要的时候再调用。
- std::function一般要绑定一个可调用对象,类成员函数不能被绑定。而std::bind更加强大,成员函数、成员变量等都能绑定。
现在通过std::function和std::bind的配合,所有的可调用对象都有了统一的操作方法。
应用
至此,我们已经详细的讲解了function类模板与std::bind,接下来具体看看他们的使用场景
模拟muduo使用bind与function模板创建线程池-CSDN博客
相关文章:
c++可调用对象、function类模板与std::bind
函数调用与函数调用运算符 先写一个简单的函数,如下: /*函数的定义*/ int func(int i) {cout<<"这是一个函数\t"<<i<<endl; }void test() {func(1);//函数的调用 } 通过这个普通的函数可以看到,调用一个函数很…...
【高危】Apache Solr 环境变量信息泄漏漏洞
漏洞描述 Apache Solr 是一款开源的搜索引擎。 在 Apache Solr 受影响版本中,由于 Solr Metrics API 默认输出所有未单独配置保护策略的环境变量。在默认无认证或具有 metrics-read 权限的情况下,攻击者可以通过向 /solr/admin/metrics 端点发送恶意请…...
Python中的卷积神经网络(CNN)入门
卷积神经网络(Convolutional Neural Networks, CNN)是一类特别适用于处理图像数据的深度学习模型。在Python中,我们可以使用流行的深度学习库TensorFlow和Keras来创建和训练一个CNN模型。在本文中,我们将介绍如何使用Keras创建一个…...
vulnhub靶机HotelWW
下载地址:https://download.vulnhub.com/worstwesternhotel/HotelWW.ova 主机发现 目标142 端口扫描 服务版本扫描 漏洞扫描 看一下web 好好好这么玩改host 啥也没有先做个目录爆破 扫描太慢我就没看了看几个重点的txt(robot,config,readme&…...
ArcGIS Pro 标注牵引线问题
ArcGIS Pro 标注 模仿CAD坐标牵引线问题 右键需要标注的要素,进入标注属性。 选择背景样式 在这里有可以选择的牵引线样式 选择这一个,可以根据调整间距来进行模仿CAD标注样式。 此图为cad样式 此为调整后gis样式 此处可以调整牵引线的样式符号 …...
Java8的Stream最佳实践
从这一篇文章开始,我们会由浅入深,全面的学习stream API的最佳实践(结合我的使用经验),本想一篇写完,但写着写着发现需要写的内容太多了,所以分成一个系列慢慢来说。给大家分享我的经验的同时&a…...
Spark SQL函数定义
目录 窗口函数 SQL函数分类 Spark原生自定义UDF函数 Pandas的UDF函数 Apache Arrow框架基本介绍 基于Arrow完成Pandas DataFrame和Spark DataFrame互转 基于Pandas完成UDF函数 自定义UDF函数 自定义UDAF函数 窗口函数 分析函数 over(partition by xxx order by xxx [as…...
触摸屏监控双速电动机-PLC I/O电路设计
PLC的输入接线电路图 PLC的输入接线电路如图1-21所示。24VDC电源选用0.7mm2的棕色和蓝色软铜导线,弱电信号线用0.5~0.7mm2的黑色或者白色软铜导线。 PLC输入接线图 PLC的输出接线电路图 PLC的输出接线电路如图1-22所示。AC220V接触器型号为CJX2-12,线…...
idea中使用git提交代码报 Nothing To commit No changes detected
问题描述 在idea中右键,开始将变更的代码进行提交的时候,【Commit Directory】点击提交的时候 报 Nothing To commit No changes detected解决方案 在这里点击Test 看看是不是能下面显示git版本,不行的话 会显示一个 fix的字样,行…...
基于长短期神经网络的回归分析,基于LSTM的回归预测
目录 背影 摘要 LSTM的基本定义 LSTM实现的步骤 基于长短期神经网络LSTM的回归分析 MATALB代码:基于长短期神经网络的回归分析,基于LSTM的回归预测资源-CSDN文库 https://download.csdn.net/download/abc991835105/88184633 效果图 结果分析 展望 参考论文 背影 LSTM神经…...
mac查看maven版本报错:The JAVA_HOME environment variable is not defined correctly
终端输入mvn -version报错: The JAVA_HOME environment variable is not defined correctly, this environment variable is needed to run this program. Java环境变量的问题,打开bash_profile查看 open ~/.bash_profile export JAVA_8_HOME/Library/Java/JavaVirtualMachine…...
蓝桥杯省赛无忧 编程9
#include<bits/stdc.h> using namespace std; int main() {int n,k,ans0;cin>>n>>k;while(n--){int a;cin>>a;ansa&1;}if(ans&1) cout<<"Alice"<<\n;else cout<<"Bob"; return 0; }这个游戏是基于数…...
Spring data都包含哪些内容
Spring Data是一个涵盖了对多种数据库访问技术的支持的项目集合,旨在提供一致的数据访问方式,简化数据访问层(DAO层)的开发工作。Spring Data项目为许多不同类型的数据存储提供了易于使用的接口和模式。主要包括以下几个方面&…...
unity 利用Graphics.Blit来制作图片效果
c# 的代码 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;public class GraphicsBlitTest : MonoBehaviour {public Texture2D source;//原纹理public Material material;//效果材质public RawImage rawImage;// Sta…...
Linux ---- 小玩具
目录 一、安装: 1、佛祖保佑,永不宕机,永无bug 2、小火车 3、艺术字和其它 天气预报 艺术字 4、会说话的小牦牛 5、其他趣味图片 我爱你 腻害 英雄联盟 帅 忍 龙 你是猪 福 好运连连 欢迎 加油 想你 忘不了你 我错了 你…...
练习题 有奖问答
题目 问题描述 小蓝正在参与一个现场问答的节目。活动中一共有 3030 道题目, 每题只有答对和答错两种情况, 每答对一题得 10 分,答错一题分数归零。 小蓝可以在任意时刻结束答题并获得目前分数对应的奖项,之后不能再答任何题目。最高奖项需要 100 分,…...
php 文件操作
目录 1.file_xxx 2.fopen 1.file_xxx 文件读写的内容都是字符串数据格式 readfile(); //读取文件内容,并返回文件的长度 file_get_contents(文件路径); //读取文件。支持本地文件和远程文件url file_put_contents(文件路径, 内容); //写入数据,保存…...
Next-GPT: Any-to-Any Multimodal LLM
Next-GPT: Any-to-Any Multimodal LLM 最近在调研一些多模态大模型相关的论文,发现Arxiv上出的论文根本看不过来,遂决定开辟一个新坑《一页PPT说清一篇论文》。自己在读论文的过程中会用一页PPT梳理其脉络和重点信息,旨在帮助自己和读者快速了…...
Angular系列教程之MVC模式和MVVM模式
文章目录 MVC模式MVVM模式MVC与MVVM的区别Angular如何实现MVVM模式总结 在讨论Angular的时候,我们经常会听到MVC和MVVM这两种设计模式。这两种模式都是为了将用户界面(UI)和业务逻辑分离,使得代码更易于维护和扩展。在这篇文章中,我们将详细介…...
windows虚拟主机和linux虚拟主机的区别有哪些?
很多个人站长和中小企业在做网站的时候,会选择虚拟主机。虚拟主机用的操作系统多为Windows系统,很多人一提到操作系统立马联想到Windows系统。其实除了Windows系统外,还有很多的操作系统。其中Linux系统是其中的佼佼者。 1、操作系统 window…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...



