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

C++ 11 【可变参数模板】【lambda】

💓博主CSDN主页:麻辣韭菜💓

⏩专栏分类:C++修炼之路

🚚代码仓库:C++高阶🚚

🌹关注我🫵带你学习更多C++知识
  🔝🔝

目录

 

前言

 一、新的类功能 

1.1默认成员函数——移动构造、移动赋值

1.2强制生成默认函数的关键字default:

1.3const延长生命周期的问题

 1.4禁止生成默认函数的关键字delete:

1.5 其他新功能

缺省值

 委托构造

二、可变参数模板 

利用递归函数展开

逗号表达式展开参数包

三、Lambda 

lambda表达式

 lambda表达式语法

 1.捕捉列表

函数对象与lambda表达式 


 

前言

上篇重点讲解了右值引用,本篇的可变参数模板Lambda也是11里面非常有用的。如果学会这两个以后编程会感觉非常的爽。废话不多说直接开始!!!

 一、新的类功能 

1.1默认成员函数——移动构造、移动赋值

在C++11后,类又新增了两个默认成员函数:移动构造移动赋值

针对移动构造函数和移动赋值运算符重载有一些需要注意的点如下:
  
  • 如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任 意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类 型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造, 如果实现了就调用移动构造,没有实现就调用拷贝构造。

  • 如果你没有自己实现移动赋值重载函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中 的任意一个,那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数,对于内 置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋 值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造 完全类似)
  • 如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。
#include "String.h"class Person
{
public:Person(const char* name = "", int age = 0):_name(name), _age(age){}/*Person(const Person& p):_name(p._name),_age(p._age){}*//*Person& operator=(const Person& p){if(this != &p){_name = p._name;_age = p._age;}return *this;}*//*~Person(){}*/private:gx::string _name;int _age;
};
int main()
{Person s1;Person s2 = s1;Person s3 = move(s1);Person s4;s4 = move(s2);return 0;
}

如果把上面代码的拷贝构造 赋值重载、析构的任意一个代码注释取消注释就会得到下面结果

为什么我们一但自己写了默认成员函数编译器就不会自己生成移动构造、赋值? 

 如果我们实现了 析构、拷贝构造、赋值重载,就证明当前的类中涉及到了 动态内存管理,是需要自己进行 深拷贝 的,编译器无能为力,移动语义 也应该根据自己的实际场景进行设计,所以编译器就没有自动生成

 那如果有些场景就需要我们自己写拷贝构造、析构、赋值重载这些函数那怎么办?

1.2强制生成默认函数的关键字default:

Person(Person&& p) = default;
Person& operator=(Person&& p) = default;

C++11后STL中所有容器都增加了移动构造和移动赋值

插入系列的函数也同样增加了右值的版本。

 其他容器详情请看官网cplusplus.com 

1.3const延长生命周期的问题

插入函数之所以会延长生命周期

当您创建一个临时对象并将其作为参数传递给函数时,这个临时对象的生命周期通常只在表达式中有效。一旦表达式结束,临时对象就会被销毁。但是,如果这个临时对象被传递给一个需要更长时间使用它的函数,比如一个需要对对象进行修改的函数,那么就需要延长这个临时对象的生命周期。

在C++中,如果一个函数的参数是一个const类型,这意味着函数不会修改这个对象。但是,如果这个参数是通过引用传递的,那么即使它是const,它仍然需要在函数调用期间保持有效,以便函数可以访问它。这就是所谓的生命周期延长。

既然可以延长对象生命周期那是不是也可以像这样?下图这样返回的对象加const

从结果来看显然是不可以的。出现了野引用的问题。 所以说引用也不是安全的。

 1.4禁止生成默认函数的关键字delete:

如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且只声明补丁
已,这样只要其他人想要调用就会报错。在C++11中更简单,只需在该函数声明加上=delete
可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。

 

在person类中我们在拷贝构造函数后面加 =delete 就无法再使用这个这个函数。

注意:delete这个关键字只对默认成员函数有效

那什么样的类是不希望其他人来调用的它的默认成员函数?

比如IO流

 

每个IO流对象的缓冲区都是不一样的,随意拷贝都会造成资源混乱。

1.5 其他新功能

在C++98中,类中的内置类型是不对初始化的。而在C++11中出现了缺省参数 可以给类的成员给缺省值。

缺省值

 没有缺省值我们得到_a的值是随机值。

给定缺省值 1

 委托构造

什么是委托构造? 简单来说就是一个构造函数可以复用其他构造函数

class Person
{
public:Person(const char* name, int age):_name(name), _age(age){}Person(const char* name):Person(name, 18) // 委托构造{}private:gx::string _name; // 自定义类型int _age = 1;		   // 内置类型
};int main()
{Person s1("张三");return 0;
}

 

这个委托构造了解一下就行了,说白了还是要调用构造函数。 

二、可变参数模板 

相比C++98的模板参数,C++11模板参数变成了不是固定的,可以接受任意个类型。和printf函数的可变参数列表是类似的。只是这里的模板参数变成了类型。

下面就是一个基本可变参数的函数模板 

// Args是一个模板参数包,args是一个函数形参参数包
// 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。
template <class ...Args>
void ShowList(Args... args)
{}

如果要知道参数包中个数怎么解决?

template<class ...Args>
void ShowList(Args...args)
{cout << sizeof...(args) << endl;
}
int main()
{ShowList(1, 'x');
}

 如何解析出参数包里面的值?

由于语法不支持使用args[i]这样方式获取可变参数,所以我们的用一些奇招来一一获取参数包的值。

利用递归函数展开

void ShowList()
{cout << endl;
}
template <class T ,class ...Args>
void ShowList(const T& val, Args ...args)
{cout << __FUNCTION__ << "(" << sizeof...(args) << ")" << endl;cout << val << endl;ShowList(args...); //语法规定...必须在后面
}
int main()
{ShowList(1, 'A', std::string("sort"));return 0;
}

 上面结果确实调用3次ShowList这个函数再加上无参ShowList。

能不能不用模板参数T? 我就想直接用可变模板参数包?可以 。直接再套一层。

void _ShowList()
{cout << endl;
}
template <class T, class ...Args>
void _ShowList(const T& val, Args... args)
{cout << __FUNCTION__ << "(" << sizeof...(args) << ")" << endl;cout << val  << endl;_ShowList(args...);
}
template <class ...Args>
void ShowList(Args... args)
{_ShowList(args...);
}int main()
{ShowList(1, 'A', std::string("sort"));return 0;
}

逗号表达式展开参数包

template <class T>
void PrintArg(T t)
{cout << t << " ";
}
//展开函数
template <class ...Args>
void ShowList(Args... args)
{int arr[] = { (PrintArg(args), 0)... };cout << endl;
}
int main()
{ShowList(1);ShowList(1, 'A');ShowList(1, 'A', std::string("sort"));return 0;
}

在上篇的初始化列表 我们知道C++11在arr这个数组创建时,会初始化 列表里面的内容。实现的关键是逗号表达式。我们知道逗号表达式会按顺序执行逗号前面的表达式。 

编译器通过解析变成下面表达式

{(printarg(args), 0)...}将会展开成((printarg(arg1),0), (printarg(arg2),0), (printarg(arg3),0), etc... )

为什么要写出成 (Print(args), 0) 的形式?
这是一个逗号表达式,目的是让整个式子最终返回 0,用于初始化 arr 数组

 如果不想加0也是可以的。

 可变参数模板应用场景又是什么?线程

我们知道C语言中回调函数的传参。C的方案是用的void*   而C++11的线程库用可变参数模板对void* 这个指针进行封装。通过可变参数模板,就可以快乐的传递任何参数。剩下的事交给编译器来干。

可变参数包还可以用于优化STL容器中插入函数。

以容器list为例:

int main()
{list<gx::string> lt;gx::string s1("1111");lt.push_back(s1);lt.emplace_back(s1);return 0;
}

 

对于是深拷贝的类是没区别的。push_back和emplace_back二者没什么区别。

我们在来看看浅拷贝的类有没有影响

#include "Date.h"
int main()
{/*list<gx::string> lt;gx::string s1("1111");lt.push_back(s1);lt.emplace_back(s1);*/list<Date> lt2;Date d1(2024, 5, 20);Date d2(2024, 5, 21);lt2.push_back(d1);lt2.emplace_back(d2);return 0;}

也是没有差别。

那如果是 d1\d2是右值那?

也是没区别

但是是下面这种就有区别了

emplace_back直接就是构造。这是因为可变参数包在参数传递的过程中,参数包不会展开。直到构造函数才展开。其实这里可以理解成(2023,5,28)它不是一个匿名对象,在参数包的眼里它实际是3个整型。

再比如 下面这个。

有了可变参数包。编译器直接识别为const char* 的字符串。而不是一个匿名对象。 

结论:无脑用emplace_back就行。

三、Lambda 

在C++11之前,我们如果要对数据进行排序怎么做?用std::sort。

#include <algorithm>
#include <functional>
int main()
{int array[] = { 4,1,8,5,3,7,0,9,2,6 };// 默认按照小于比较,排出来结果是升序std::sort(array, array + sizeof(array) / sizeof(array[0]));// 如果需要降序,需要改变元素的比较规则std::sort(array, array + sizeof(array) / sizeof(array[0]), greater<int>());return 0;
}

如果我们要排序的是自定义类型那就需要用到仿函数。

struct Goods
{string _name;  // 名字double _price; // 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){}
};
struct ComparePriceLess
{bool operator()(const Goods& gl, const Goods& gr){{return gl._price < gr._price;}	}
};
struct ComparePriceGreater
{bool operator()(const Goods& gl, const Goods& gr){return gl._price > gr._price;}
};
int main()
{vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,3 }, { "菠萝", 1.5, 4 } };sort(v.begin(), v.end(), ComparePriceLess());sort(v.begin(), v.end(), ComparePriceGreater());
}

 生活中商品太多了难道每一种商品的排序都要写相应的仿函数,是不是有点太麻烦?,假设我们不以价格来进行排序。现在要求按水果的名字排序,是不是又要重写一个仿函数?

有没有一种办法一劳永逸?在C++11推出了lambda 

lambda表达式

int main()
{vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,3 }, { "菠萝", 1.5, 4 } };sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {return g1._price < g2._price; });sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {return g1._price > g2._price; });sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {return g1._evaluate < g2._evaluate; });sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {return g1._evaluate > g2._evaluate; });
}

 

上述代码就是使用C++11中的lambda表达式来解决,可以看出lambda表达式实际是一个匿名函

数。

 lambda表达式语法

lambda 表达式书写格式: [capture-list] (parameters) mutable -> return-type { statement
}
1. lambda 表达式各部分说明
  • [capture-list] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]
判断接下来的代码是否为 lambda 函数 捕捉列表能够捕捉上下文中的变量供 lambda
函数使用
  • (parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以
连同 () 一起省略
  • mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量
性。使用该修饰符时,参数列表不可省略 ( 即使参数为空 )
  • ->returntype:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回
值时此部分可省略。 返回值类型明确情况下,也可省略,由编译器对返回类型进行推
  • {statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获
到的变量。
注意:
lambda 函数定义中, 参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为
。因此 C++11 最简单的lambda函数为 []{} ; lambda 函数不能做任何事情。

我们先来一个简单的lambda语法

	[](int x, int y)->int {return x + y; };

 如果函数体的语句较多我们也是可以这样写代码的

	[](int x, int y)->int {return x + y; };

我们如果要调用这个函数对象太长了,我们可以加 auto 

	auto add1 = [](int x, int y)->int {return x + y; };cout << add1(1, 2) << endl;

最简单的lambda表达式

//最简单的lambda表达式 该lambda表达式没有任何意义[] {};

 1.捕捉列表

写一个交换函数。

​int x = 1, y = 0;auto swap1 = [](int& rx, int& ry){int tmp = rx;rx = ry;ry = tmp;};swap1(x, y);cout << x << " " << y << endl;

参数列表是可以省略的

省略参数时,我们就要用捕捉列表

 

这时我们可以在参数列表后面加入关键字,mutable//异变 但是没什么用

 

 还是没有交换

上面的这种捕捉方式叫做传值捕捉,传值具有常性,不能修改 这时我们需要用到引用捕捉

这里的引用捕捉就很坑,不注意看还以为是取地址!! 

 

如果参数太多怎么办?难道要在捕捉列表中一个一个的捕捉吗?当然不用。我们直接全部引用捕捉

//全部引用捕捉
auto swap2 = [&]() {int tmp = x;x = y;y = tmp;};

当然还有其他的捕捉方式

 //混合捕捉auto func1 = [&x, y](){//...};//全部传值捕捉auto func3 = [=](){//...};//全部引用捕捉,x传值捕捉auto func4 = [&, x](){//...};

 这时我们就可以用lambad来创建线程

int main()
{int n1, n2;cin >> n1 >> n2;thread t1([n1]( int num){for (int i = 0; i < n1; i++){cout << "线程:" << num << " " << i << endl;}cout << endl;},1);thread t2([n2](int num){for (int i = 0; i < n2; i++){cout << "线程:" << num << " " << i << endl;}cout << endl;}, 2);t1.join();t2.join();return 0;
}

如果要m个线程分别打印n次如何操作? 这里我们可以利用vector 把每个线程放进vector这个容器中。

#include <vector>
int main()
{int m, n;cin >> m >> n;vector<int> arr;arr.push_back(m);arr.push_back(n);vector<thread> vthds(m);for (int i = 0; i < arr[0]; i++){vthds[i] = thread([i,arr](){for (int j = 0; j< arr[1]; j++){cout << "线程:" << i << " " << j << endl;}cout << endl;});}for (auto& t : vthds){t.join();}return 0;
}

 当然这个打印会错乱,那是因为没有加锁导致线程串行。关于锁的问题我们在后序线程库在详细讲解。

lambda 能不能相互赋值?
void (*PF)();
int main()
{auto f1 = []{cout << "hello world" << endl; };auto f2 = []{cout << "hello world" << endl; };//f1 = f2;   // 编译失败--->提示找不到operator=()// 允许使用一个lambda表达式拷贝构造一个新的副本auto f3(f2);f3();// 可以将lambda表达式赋值给相同类型的函数指针PF = f2;PF();return 0;
}

总结: 

捕捉列表描述了上下文中那些数据可以被 lambda 使用 ,以及 使用的方式传值还是传引用
[var] :表示值传递方式捕捉变量 var
[=] :表示值传递方式捕获所有父作用域中的变量 ( 包括 this)
[&var] :表示引用传递捕捉变量 var
[&] :表示引用传递捕捉所有父作用域中的变量 ( 包括 this)
[this] :表示值传递方式捕捉当前的 this 指针
注意:
a. 父作用域指包含 lambda 函数的语句块
b. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割
比如: [=, &a, &b] :以引用传递的方式捕捉变量 a b ,值传递方式捕捉其他所有变量
[& a, this] :值传递方式捕捉变量 a this ,引用方式捕捉其他变量
c. 捕捉列表不允许变量重复传递,否则就会导致编译错误
比如: [=, a] = 已经以值传递方式捕捉了所有变量,捕捉 a 重复

d. 在块作用域以外的 lambda 函数捕捉列表必须为空
e. 在块作用域中的 lambda函数能捕捉父作用域中局部变量。
f. lambda 表达式之间不能相互赋值 ,即使看起来类型相同

函数对象与lambda表达式 

函数对象,又称为仿函数,即可以想函数一样使用的对象,就是在类中重载了 operator() 运算符的
类对象。

 lambda的大小是多大?

要清楚这个问题我们需要通过汇编

先搞一个函数对象和lambda的代码

class Rate
{
public:Rate(double rate) : _rate(rate){}double operator()(double money, int year){return money * _rate * year;}private:double _rate;
};
int main()
{// 函数对象double rate = 0.49;Rate r1(rate);r1(10000, 2);// lambdaauto r2 = [=](double monty, int year)->double {return monty * rate * year; };r2(10000, 2);auto f1 = [] {cout << "hello world" << endl; };auto f2 = [] {cout << "hello world" << endl; };//f1 = f2;return 0;
}

 

f1 和 f2通过汇编我们发现他们两个类名不同,类名不同怎么相互赋值?

这时候我们就能回答大小为什么是1了

在C++中,sizeof运算符用来确定一个类型或对象在内存中的大小。对于一个lambda表达式,sizeof返回的是这个lambda表达式对象在内存中占用的大小。

在x86 32位架构上,指针通常是4字节大小。因此,如果你的lambda表达式没有捕获任何局部变量或外部变量(或者只捕获了通过引用捕获的变量),那么lambda表达式的大小很可能是1字节,这是因为:

  1. Lambda表达式可能被编译器优化为一个很小的函数对象,它只包含一个指向其代码的指针。
  2. 在某些编译器实现中,lambda表达式可能被优化为一个空的结构体,其中只包含一个指向其代码的指针,因此sizeof返回1,表示空结构体的大小。

相关文章:

C++ 11 【可变参数模板】【lambda】

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;C修炼之路⏪   &#x1f69a;代码仓库:C高阶&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多C知识   &#x1f51d;&#x1f51d; 目录 前言 一、新的类功能 1.1默认成员函数—…...

c 宏应用举例

1.概要 #include <iostream> //变量可以直接使用 #define fun() a 100; //用变量计算可以 #define fun2(a) a*2; //用变量替换可以 #define fun3(a) d[a] a; //##链接的作用&#xff0c;一般用于链接变量名 #define fun4(type,name) type name##_s 4; //#的作用是转换…...

微信公众号(公众平台) 和 微信开放平台的scope的差异

微信公众号&#xff08;公众平台&#xff09; 和 微信开放平台 是两码事。 公众号&#xff08;公众平台&#xff09;获取的scope只包括两种&#xff1a;snsapi_base 和snsapi_userinfo&#xff0c;前者是静默获取&#xff0c;用户无感知&#xff1b;后者是需要用户确认同意的。…...

基于pytorch实现的DenseUnet医学图像分割(腹部多脏器)

1、前言 本章将介绍将densenet的主干网络引入unet中 官方实现的代码&#xff1a;kits19-challenge/network at master nitsaick/kits19-challenge (github.com) 本章实现的项目目录如下&#xff1a; 主要代码有train、evaluate、predict脚本 2、代码介绍 数据预处理脚本 数据…...

富格林:正规策划实现安全做单

富格林悉知&#xff0c;在投资理财的过程中&#xff0c;最重要的是控制风险实现安全做单避免损失。但是市场客观因素带来的风险并不能完全避免&#xff0c;因此投资者需要采取一些正规技能来减低风险投资风险实现安全做单。接下来就由富格林给大家分享一些实现安全做单的正规方…...

02. 异常捕捉和处理

检索特定内容的邮件&#xff0c;当检索失败&#xff0c;就会在终端输出“获取不了值” try: #代码块A except: #代码B 试一下运行代码A&#xff0c;当代码A报错时&#xff0c;执行代码B 这是main_exe.py文件中的内容 略过 #今天 for job_name,end_time in zip(bji.job_inf…...

Oracle和mysql中插入时间字段

例如有id 和 times两个字段 Oracle insert into xxx values|(1,sysdate) mysql insert into xxx values(1,now()) 在 MySQL 中&#xff0c;SYSDATE() 函数也是可用的&#xff0c;它与 NOW() 类似&#xff0c;但略有不同&#xff1a; NOW…...

注册小程序

每个小程序都需要在 app.js 中调用 App 方法注册小程序实例&#xff0c;绑定生命周期回调函数、错误监听和页面不存在监听函数等。 详细的参数含义和使用请参考 App 参考文档 。 整个小程序只有一个 App 实例&#xff0c;是全部页面共享的。开发者可以通过 getApp 方法获取到全…...

【YOLOv8改进[CONV]】使用MSBlock二次创新C2f模块实现轻量化 + 含全部代码和详细修改方式 + 手撕结构图 + 轻量化 + 涨点

本文将使用MSBlock二次创新C2f模块实现轻量化,助力YOLOv8目标检测效果的实践,文中含全部代码、详细修改方式以及手撕结构图。助您轻松理解改进的方法,实现有效涨点。 改进前和改进后的参数对比: 目录 一 MSBlock 二 使用MSBlock二次创新C2f模块实现轻量化 1 整体修改 …...

three.js使用环境贴图或者加载hdr图

1、three.js使用环境贴图 1.1、效果视频 环境贴图 1.2、使用步骤&#xff08;个人认为&#xff09; &#xff08;1&#xff09;导入引入相关方法 &#xff08;2&#xff09;创建场景 &#xff08;3&#xff09;创建相机 &#xff08;4&#xff09;添加物体材质 &#xff08;5…...

GPT-4o多模态大模型的架构设计

GPT-4o&#xff1a;大模型风向&#xff0c;OpenAI大更新 OpenAI震撼发布两大更新&#xff01;桌面版APP与全新UI的ChatGPT上线&#xff0c;简化用户操作&#xff0c;体验更自然。同时&#xff0c;全能模型GPT-4o惊艳亮相&#xff0c;跨模态即时响应&#xff0c;性能卓越且性价比…...

Facebook:社交世界的引领者

导语 在当今数字化时代&#xff0c;Facebook已经成为了人们社交生活的重要一环。然而&#xff0c;除了成为社交媒体的象征外&#xff0c;它还在不断探索并领导着社交世界的新方向。 1. 社交平台的发展者 Facebook不仅仅是一个社交平台&#xff0c;更是社交方式的引领者。从其…...

qt 加载字体 c++

目录 qt 加载字体 c label设置大小和字体&#xff1a; 资源配置路径失败 解决方法&#xff1a;exe相对目录&#xff1a; pro配置&#xff1a; resource.qrc qt 加载字体 c #include <QApplication> #include <QLabel> #include <QFontDatabase> #incl…...

Linux ldd和ldconfig

ldconfig ldconfig 查看默认库路径和ld.so.conf包含的库路径&#xff0c;来建立运行时动态装载的库查找路径。 ldconfig命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态链接库(格式如前介绍,lib*.so*),…...

Python 学习flask创建项目

1、使用pycharm创建flask项目 2、运行访问地址 3、可以看到访问地址内容 4、可以增加路由&#xff0c;尝试访问获取参数...

.NET集成DeveloperSharp实现图片的裁剪、缩放、与加水印

&#x1f3c6;作者&#xff1a;科技、互联网行业优质创作者 &#x1f3c6;专注领域&#xff1a;.Net技术、软件架构、人工智能、数字化转型、DeveloperSharp、微服务、工业互联网、智能制造 &#x1f3c6;欢迎关注我&#xff08;Net数字智慧化基地&#xff09;&#xff0c;里面…...

阿里发布最强开源大模型通义千问Qwen2,国产最好用的LLM

前言 近年来&#xff0c;大模型技术发展迅速&#xff0c;开源模型的出现为AI研究和应用带来了新的活力。在这一背景下&#xff0c;阿里云通义千问团队发布了全新升级的Qwen2系列开源模型&#xff0c;为国内外开发者提供了更强大的工具和更丰富的选择。 Huggingface模型下载&am…...

探索风电机组:关键软件工具全解析

探索风电机组&#xff1a;关键软件工具全解析 随着可再生能源市场的迅猛发展&#xff0c;风电作为一种重要的可再生能源&#xff0c;其相关技术和工具也越来越受到重视。风电机组的设计、仿真、优化及运维等方面&#xff0c;都需要依靠一系列专业软件工具来实现。这些软件涵盖…...

HOW - CSS 常见效果实现

目录 渐隐渐显曲线&抛物线气泡框水波纹悬浮&漂浮长按控制进度条圆弧&圆形进度条引导蒙层随机物品掉落渐变边框光晕按钮下压反馈头像&#xff08;圆形半透明阴影&#xff09; 常见 CSS 效果实现总结。 渐隐渐显 <!DOCTYPE html> <html> <style>…...

EI/CPCI/Scopus会议论文是啥?

EI/CPCI/Scopus会议论文是啥&#xff1f; EI/CPCI/Scopus是学术圈常见的字母缩写了&#xff0c;它们并非某一种期刊或是某一种杂志&#xff0c;而是一种便捷的论文检索工具。它们之间的区别在于&#xff0c;各自涵盖的领域的不同。▌EI &#xff08;The Engineering Index&…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...