C++进阶——C++11_{ }初始化_lambda_包装器
目录
1、{ }初始化
1.1 C++98的{ }
1.2 C++11的{ }
1.3 C++11中的std::initializer_list
总结一下:
2、lambda
2.1 lambda的语法
2.2 捕捉列表
2.3 lambda的应用
2.4 lambda的原理
3、包装器
3.1 function
3.2 bind
1、{ }初始化
1.1 C++98的{ }
C++98中一般数组和结构体可以用{ }进行初始化。
struct Point
{int _x;int _y;
};int main()
{int array1[] = {1, 2, 3, 4, 5};int array2[5] = {0};Point p = {1, 2};return 0;
}
1.2 C++11的{ }
C++11 以后想统一初始化方式,试图实现一切对象皆可用 { } 初始化,{ } 初始化也叫做列表初始化。
内置类型支持,自定义类型也支持,自定义类型本质是类型转换,中间会产生临时对象,最后优化
了以后变成直接构造。
{ } 初始化的过程中,可以省略 = 。
#include <iostream>
#include <vector>
using namespace std;struct Point
{int _x;int _y;
};class Date
{
public:Date(int year = 1, int month = 1, int day = 1): _year(year), _month(month), _day(day){cout << "Date(int year, int month, int day)" << endl;}Date(const Date& d): _year(d._year), _month(d._month), _day(d._day){cout << "Date(const Date& d)" << endl;}private:int _year;int _month;int _day;
};int main()
{// C++98 支持的初始化方式int a1[] = {1, 2, 3, 4, 5};int a2[5] = {0};Point p = {1, 2};// C++11 支持的初始化方式// 内置类型支持int x1 = {2};// 自定义类型支持// 这里本质是用 {2025, 1, 1} 构造一个 Date 临时对象// 临时对象再去拷贝构造 d1,编译器优化后合二为一变成 {2025, 1, 1} 直接构造初始化 d1// 运行一下,我们可以验证上面的理论,发现是没调用拷贝构造的Date d1 = {2025, 1, 1};// 这里 d2 引用的是 {2024, 7, 25} 构造的临时对象const Date& d2 = {2024, 7, 25};// 需要注意的是 C++98 支持单参数时类型转换,也可以不用 {}Date d3 = {2025};Date d4 = 2025;// 可以省略掉 =Point p1{1, 2};int x2{2};Date d6{2024, 7, 25};const Date& d7{2024, 7, 25};// 不支持,只有 {} 初始化,才能省略 =// Date d8 2025;vector<Date> v;v.push_back(d1);v.push_back(Date(2025, 1, 1));// 比起有名对象和匿名对象传参,这里 {} 更有性价比v.push_back({2025, 1, 1});return 0;
}
1.3 C++11中的std::initializer_list
但是对象容器初始化还是不太方便,比如一个vector对象,我想用N个值去构造初始化,那么我们得实现很多个构造函数才能支持,
vector<int> v1 = {1, 2, 3};
vector<int> v2 = {1, 2, 3, 4, 5};
C++11 库中提出了一个 std::initializer_list 的类,
auto il = { 10, 20, 30 }; // the type of il is an initializer_list
这个类的本质是底层开一个数组,将数据拷贝过来,std::initializer_list 内部有两个指针分别指向数组的开始和结束,支持迭代器遍历。
这是它的文档:initializer_list - C++ Reference 。
容器支持一个 std::initializer_list 的构造函数,也就支持任意多个值构成的初始化。STL 中的容器支持用 {x1, x2, x3...} 进行初始化,就是通过 std::initializer_list 的构造函数支持的。
// 标准库中的声明示例// vector 的 initializer_list 构造函数
vector(initializer_list<value_type> il, const allocator_type& alloc = allocator_type());// list 的 initializer_list 构造函数
list(initializer_list<value_type> il, const allocator_type& alloc = allocator_type());// map 的 initializer_list 构造函数
map(initializer_list<value_type> il,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());// 自定义 vector 的简化实现
template<class T>
class vector {
public:typedef T* iterator; // 迭代器类型// initializer_list 构造函数vector(initializer_list<T> il) {for (auto& e : il) { // 遍历列表元素push_back(e); // 逐个插入容器}}private:iterator _start = nullptr; // 指向首元素iterator _finish = nullptr; // 指向最后一个元素的下一个位置iterator _endofstorage = nullptr; // 指向存储空间的末尾
};
#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;int main() {// 1. 测试 initializer_list 的基本特性std::initializer_list<int> mylist;mylist = {10, 20, 30}; // 初始化列表赋值// 输出 initializer_list 的大小(通常是固定大小,包含两个指针)cout << "sizeof(mylist): " << sizeof(mylist) << endl;// 2. 验证 initializer_list 的存储位置int i = 0;cout << "mylist.begin(): " << mylist.begin() << endl; // 指向第一个元素cout << "mylist.end(): " << mylist.end() << endl; // 指向末尾后一位cout << "&i: " << &i << endl; // 对比栈地址// 3. 容器的两种初始化方式对比vector<int> v1({1, 2, 3, 4, 5}); // 直接构造(显式 initializer_list)vector<int> v2 = {1, 2, 3, 4, 5}; // 隐式转换(可能触发拷贝优化)const vector<int>& v3 = {1, 2, 3, 4, 5}; // 引用临时对象(生命周期延长)// 4. map 的嵌套初始化(pair + initializer_list)map<string, string> dict = {{"sort", "排序"}, {"string", "字符串"}};// 5. initializer_list 赋值操作v1 = {10, 20, 30, 40, 50}; // 调用 operator=(initializer_list)return 0;
}
总结一下:
C++11,基本实现了一切对象皆可初始化。
2、lambda
2.1 lambda的语法
lambda 表达式本质是一个匿名函数对象,跟普通函数不同的是它可以定义在函数内部。
lambda 表达式语法层面而言没有类型,所以我们一般是用auto或者模板参数定义的对象去接收。
lambda 表达式的格式:
[capture-list] (parameters) -> return type { function body }
[capture-list]:捕捉列表,编译器根据 [ ] 来判断是否为 lambda 函数。捕捉列表能够捕捉上下文中的变量供 lambda 函数使用,捕捉列表可以传值和传引用捕捉,具体细节在 2.2 中我们再细讲。捕捉列表为空 [ ] 也不能省略。
(parameters):参数列表,与普通函数的参数列表功能类似,如果不需要参数传递,则可以连同( )一起省略。
-> return type:返回值类型,用追踪返回类型形式(允许将函数的返回类型放在参数列表之后(用->引导))声明函数的返回值类型,没有返回值时此部分可省略。一般返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。
{ function body }:函数体,函数体内的实现跟普通函数完全类似,在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量,函数体为空{ }也不能省略。
#include <iostream>
using namespace std;int main() {// 1. 一个简单的lambda表达式auto add1 = [](int x, int y)->int { return x + y; };cout << add1(1, 2) << endl; // 输出: 3/* Lambda表达式特性说明:1. 捕捉列表为空也不能省略(必须写[])2. 参数列表为空可以省略(如func1示例)3. 返回值可以省略,可以通过返回对象自动推导4. 函数体不能省略*/// 2. 无参数、无显式返回类型的lambdaauto func1 = [] {cout << "hello bit" << endl;return 0;};func1(); // 输出: hello bit// 3. 通过引用修改外部变量int a = 0, b = 1; auto swap1 = [](int& x, int& y) {int tmp = x;x = y;y = tmp;};swap1(a, b);cout << a << ":" << b << endl; // 输出: 1:0return 0;
}
2.2 捕捉列表
Lambda 表达式的变量捕捉规则
在 lambda 表达式中,默认只能使用 lambda 函数体和参数中的变量。如果想使用外层作用域中的变量,就需要进行捕捉。
第一种捕捉方式:显式捕捉
在捕捉列表中显式指定 传值捕捉 和 传引用捕捉,多个变量用逗号分隔。
[x, y, &z] 表示 x 和 y 值捕捉,z 引用捕捉。
第二种捕捉方式:隐式捕捉
[=] 表示 隐式值捕捉,[&] 表示 隐式引用捕捉。
lambda 表达式中使用了哪些变量,编译器就会自动捕捉哪些变量。即按需捕捉。
第三种捕捉方式:混合捕捉
在捕捉列表中 混合使用隐式捕捉和显式捕捉:
[=, &x] 表示其他变量 隐式值捕捉,x 引用捕捉。
[&, x, y] 表示其他变量 隐式引用捕捉,x 和 y 值捕捉。
混合捕捉规则:
-
第一个元素必须是 & 或 =。
-
& 混合捕捉时,后面的捕捉变量必须是 值捕捉。
-
= 混合捕捉时,后面的捕捉变量必须是 引用捕捉。
Lambda 表达式的变量作用域规则
-
如果 lambda 表达式定义在函数局部作用域,它可以捕捉 lambda 位置之前定义的局部变量,但不能捕捉 静态局部变量 和 全局变量(它们可以直接使用,无需捕捉)。
-
如果 lambda 表达式定义在全局位置,捕捉列表必须为空(不能捕捉任何变量)一般也不会定义在全局。
Lambda 的 const 性和 mutable 修饰
-
默认情况下,传值捕捉是被 const 修饰的,即 传值捕捉的变量不能修改。引用捕捉没有const修饰。
-
使用 mutable 修饰符(加在参数列表后面)可以取消 const 限制,使 传值捕捉的变量可以修改(但修改的是形参,不影响实参)。
-
使用 mutable 后,参数列表()不可省略(即使参数为空)。
#include <iostream>
using namespace std;int x = 0; // 全局变量// 全局lambda的捕捉列表必须为空(全局变量可直接使用,无需捕捉)
auto func_global = []() {x++; // 直接修改全局变量
};int main() {// 局部变量int a = 0, b = 1, c = 2, d = 3;// 1. 显式捕捉:值捕捉a,引用捕捉bauto func1 = [a, &b] {// a++; // 错误:值捕捉的变量默认const,不可修改b++; // 正确:引用捕捉可修改return a + b;};cout << func1() << endl;// 2. 隐式值捕捉(=):自动捕捉所有使用的局部变量(a,b,c)auto func2 = [=] {return a + b + c; // d未使用,不会被捕捉};cout << func2() << endl;// 3. 隐式引用捕捉(&):自动引用捕捉所有修改的变量auto func3 = [&] {a++; c++; d++; // 全部通过引用修改};func3();cout << a << " " << b << " " << c << " " << d << endl;// 4. 混合捕捉1:默认引用捕捉,显式值捕捉a,bauto func4 = [&, a, b] {// a++; b++; // 错误:a,b是值捕捉c++; d++; // 正确:其他变量隐式引用捕捉return a + b + c + d;};func4();cout << a << " " << b << " " << c << " " << d << endl;// 5. 混合捕捉2:默认值捕捉,显式引用捕捉a,bauto func5 = [=, &a, &b] {a++; b++; // 正确:a,b是引用捕捉// c++; d++; // 错误:其他变量隐式值捕捉return a + b + c + d;};func5();cout << a << " " << b << " " << c << " " << d << endl;// 6. 静态/全局变量无需捕捉static int m = 0;auto func6 = [] {return x + m; // 直接使用全局和静态变量};// 7. mutable修饰:允许修改值捕捉的副本(不影响外部变量)auto func7 = [=]() mutable {a++; b++; c++; d++; // 修改的是内部副本return a + b + c + d;};cout << func7() << endl; // 输出副本修改后的值cout << a << " " << b << " " << c << " " << d << endl; // 原变量不变return 0;
}
2.3 lambda的应用
在学习 lambda 表达式之前,我们使用的可调用对象只有函数指针和仿函数对象,函数指针的
类型定义起来比较麻烦,仿函数要定义一个类,相对会比较麻烦。使用 lambda 去定义可调用对象,既简单方便。
lambda 在很多其他地方用起来也很好用。比如线程中定义线程的执行函数逻辑,智能指针中定
制删除器等,lambda 的应用还是很广泛的,以后我们会不断接触到。
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 } };// 类似这样的场景,我们实现仿函数对象或者函数指针支持商品中// 不同项的⽐较,相对还是⽐较⿇烦的,那么这⾥ lambda 就很好⽤了sort(v.begin(), v.end(), ComparePriceLess());sort(v.begin(), v.end(), ComparePriceGreater());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;});return 0;
}
2.4 lambda的原理
lambda 的原理和范围 for 相似,编译后从汇编指令层的角度看,压根就没有 Lambda 和范围 for 这样的东西。范围 for 底层是迭代器,而 lambda 底层是仿函数对象,也就是说我们写了一个 lambda 以后,编译器会生成一个对应的仿函数的类。
仿函数的类名是编译器按一定规则生成的,保证不同的 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;// lambda 表达式auto r2 = [rate](double money, int year) {return money * rate * year;};// 函数对象(仿函数)Rate r1(rate);r1(10000, 2); // 调用仿函数r2(10000, 2); // 调用 lambda// 无参 lambdaauto func1 = [] {cout << "hello world" << endl;};func1(); // 调用无参 lambdareturn 0;
}
// lambda 表达式
auto r2 = [rate](double money, int year) {return money * rate * year;
};// 捕捉列表的 `rate`,可以看到作为 `lambda_1` 类构造函数的参数传递了,
// 这样在初始化成员变量后,才能在下面的 operator() 中使用
//
// 汇编代码片段:
// 00D8295C lea eax,[rate]
// 00D8295F push eax
// 00D82960 lea ecx,[r2]
// 00D82963 call `main'::`2'::<lambda_1>::<lambda_1> (0D81F80h) // 函数对象(仿函数)
Rate r1(rate);
// 汇编代码片段:
// 00D82968 sub esp,8
// 00D8296B movsd xmm0,mmword ptr [rate]
// 00D82970 movsd mmword ptr [esp],xmm0
// 00D82975 lea ecx,[r1]
// 00D82978 call Rate::Rate (0D81438h) r1(10000, 2);
// 汇编代码片段:
// 00D8297D push 2
// 00D8297F sub esp,8
// 00D82982 movsd xmm0,mmword ptr [__real@40c3880000000000 (0D89B50h)]
// 00D8298A movsd mmword ptr [esp],xmm0
// 00D8298F lea ecx,[r1]
// 00D82992 call Rate::operator() (0D81212h) // 从汇编层可以看到,r2(lambda 对象)的调用本质还是调用 operator(),
// 其类型是 `lambda_1`,这个类型名的规则由编译器自定义,确保不同的 lambda 不冲突
r2(10000, 2);
// 汇编代码片段:
// 00D82999 push 2
// 00D8299B sub esp,8
// 00D8299E movsd xmm0,mmword ptr [__real@40c3880000000000 (0D89B50h)]
// 00D829A6 movsd mmword ptr [esp],xmm0
// 00D829AB lea ecx,[r2]
// 00D829AE call `main'::`2'::<lambda_1>::operator() (0D824C0h)
3、包装器
3.1 function
1. std::function 是一个类模板,也是一个包装器。
2. std::function 的实例对象可以包装存储其他的可调用对象,包括函数指针、仿函数、lambda 等,统一类型,存储的可调用对象被称为 std::function 的目标。若 std::function 不含目标,则称它为空。调用空 std::function 的目标会导致抛出 std::bad_function_call 异常。
// 前置声明(未定义的通用模板)
template <class T>
class function; // undefined base template// 特化版本:支持函数类型签名(返回类型 + 参数列表)
template <class Ret, class... Args>
class function<Ret(Args...)> {// 实现内容(此处未展开)// 通常包含 operator() 以支持函数调用
};
以上是 std::function 的原型,它被定义在 <functional> 头文件中。
官方文档:std::function - cppreference.com
#include <functional>
#include <iostream>
using namespace std;// 普通函数
int f(int a, int b) {return a + b;
}// 仿函数(函数对象)
struct Functor {int operator()(int a, int b) {return a + b;}
};// 类(包含静态和非静态成员函数)
class Plus {
public:Plus(int n = 10) : _n(n) {}// 静态成员函数static int plusi(int a, int b) {return a + b;}// 非静态成员函数(依赖 this 指针)double plusd(double a, double b) {return (a + b) * _n;}private:int _n;
};int main() {// 1. 包装普通函数function<int(int, int)> f1 = f;cout << f1(1, 1) << endl; // 输出: 2// 2. 包装仿函数对象function<int(int, int)> f2 = Functor();cout << f2(1, 1) << endl; // 输出: 2// 3. 包装 lambda 表达式function<int(int, int)> f3 = [](int a, int b) { return a + b; };cout << f3(1, 1) << endl; // 输出: 2// 4. 包装静态成员函数(无需对象实例)function<int(int, int)> f4 = &Plus::plusi;cout << f4(1, 1) << endl; // 输出: 2// 5. 包装非静态成员函数(需绑定对象)Plus pd(10); // _n = 10// 方式1:传递对象指针function<double(Plus*, double, double)> f5 = &Plus::plusd;cout << f5(&pd, 1.1, 1.1) << endl; // 输出: (1.1 + 1.1) * 10 = 22// 方式2:传递对象值(拷贝)function<double(Plus, double, double)> f6 = &Plus::plusd;cout << f6(pd, 1.1, 1.1) << endl; // 输出: 22// 方式3:传递右值引用function<double(Plus&&, double, double)> f7 = &Plus::plusd;cout << f7(move(pd), 1.1, 1.1) << endl; // 输出: 22cout << f7(Plus(10), 1.1, 1.1) << endl; // 输出: 22(临时对象)return 0;
}
静态成员函数不属于对象,不需要传this指针,非静态成员函数需传递this指针,传递对象(会自行取对象地址)或对象地址。
3.2 bind
1. 基本形式(自动推导返回类型)
template <class Fn, class... Args>
/* unspecified */ bind(Fn&& fn, Args&&... args);
2. 指定返回类型(C++14 起支持)
template <class Ret, class Fn, class... Args>
/* unspecified */ bind(Fn&& fn, Args&&... args);
bind 是一个函数模板,它也是一个可调用对象的包装器,可以把它看做一个函数适配器( 封装函数/可调用对象),对接收 的 fn 可调用对象进行处理后返回一个可调用对象。
bind 可以用来调整参数个数和参数顺序。bind 也在<functional>这个头文件中。
调用 bind 的一般形式: auto newCallable = bind(callable,arg_list); 其中 newCallable 本身是一个可调用对象,arg_list 是一个逗号分隔的参数列表,对应给定的 callable 的 参数。当我们调用 newCallable 时,newCallable 会调用 callable,并传给它 arg_list 中的参数。
arg_list 中的参数可能包含形如 _n 的名字,其中 n 是一个整数,表示 newCallable 的参数。数值 n 表示生成的可调用对象中参数的位置:_1 为 newCallable 的第一个参数(无所谓_1的位置在哪),_2 为第二个参数,以此类推。_1/_2/_3.... 这些占位符放在 placeholders 的一个命名空间中。
#include <iostream>
#include <functional>// 定义一个减法函数,返回 (a - b) * 10
int Sub(int a, int b) {return (a - b) * 10;
}// 定义一个减法函数,返回 (a - b - c) * 10
int SubX(int a, int b, int c) {return (a - b - c) * 10;
}// 定义一个 Plus 类,包含静态和非静态的加法函数
class Plus {
public:// 静态加法函数static int plusi(int a, int b) {return a + b;}// 非静态加法函数double plusd(double a, double b) {return a + b;}
};int main() {// 使用 std::placeholders 命名空间中的占位符using namespace std::placeholders;// 绑定 Sub 函数,正常顺序传递参数auto sub1 = std::bind(Sub, _1, _2);std::cout << sub1(10, 5) << std::endl;// 调整参数顺序,交换 _1 和 _2 的位置auto sub2 = std::bind(Sub, _2, _1);std::cout << sub2(10, 5) << std::endl;// 调整参数个数,固定第一个参数为 100auto sub3 = std::bind(Sub, 100, _1);std::cout << sub3(5) << std::endl;// 调整参数个数,固定第二个参数为 100auto sub4 = std::bind(Sub, _1, 100);std::cout << sub4(5) << std::endl;// 分别绑死 SubX 函数的第 1、2、3 个参数auto sub5 = std::bind(SubX, 100, _1, _2);std::cout << sub5(5, 1) << std::endl;auto sub6 = std::bind(SubX, _1, 100, _2);std::cout << sub6(5, 1) << std::endl;auto sub7 = std::bind(SubX, _1, _2, 100);std::cout << sub7(5, 1) << std::endl;// 绑定 Plus 类的非静态成员函数std::function<double(Plus&&, double, double)> f6 = &Plus::plusd;Plus pd;std::cout << f6(std::move(pd), 1.1, 1.1) << std::endl;std::cout << f6(Plus(), 1.1, 1.1) << std::endl;// 使用 std::bind 绑定 Plus 类的非静态成员函数,固定对象std::function<double(double, double)> f7 = std::bind(&Plus::plusd, Plus(), _1, _2);std::cout << f7(1.1, 1.1) << std::endl;// 定义一个计算复利的 lambda 函数auto func1 = [](double rate, double money, int year) -> double {double ret = money;for (int i = 0; i < year; i++) {ret += ret * rate;}return ret - money;};// 绑死一些参数,实现支持不同年利率、不同金额和不同年份计算复利的结算利息std::function<double(double)> func3_1_5 = std::bind(func1, 0.015, _1, 3);std::function<double(double)> func5_1_5 = std::bind(func1, 0.015, _1, 5);std::function<double(double)> func10_2_5 = std::bind(func1, 0.025, _1, 10);std::function<double(double)> func20_3_5 = std::bind(func1, 0.035, _1, 30);std::cout << func3_1_5(1000000) << std::endl;std::cout << func5_1_5(1000000) << std::endl;std::cout << func10_2_5(1000000) << std::endl;std::cout << func20_3_5(1000000) << std::endl;return 0;
}
相关文章:
C++进阶——C++11_{ }初始化_lambda_包装器
目录 1、{ }初始化 1.1 C98的{ } 1.2 C11的{ } 1.3 C11中的std::initializer_list 总结一下: 2、lambda 2.1 lambda的语法 2.2 捕捉列表 2.3 lambda的应用 2.4 lambda的原理 3、包装器 3.1 function 3.2 bind 1、{ }初始化 1.1 C98的{ } C98中一般数组…...
十大PDF解析工具在不同文档类别中的比较研究
PDF解析对于包括文档分类、信息提取和检索在内的多种自然语言处理任务至关重要,尤其是RAG的背景下。尽管存在各种PDF解析工具,但它们在不同文档类型中的有效性仍缺乏充分研究,尤其是超出学术文档范畴。通过使用DocLayNet数据集,比…...
【LeetCode Solutions】LeetCode 160 ~ 165 题解
CONTENTS LeetCode 160. 相交链表(简单)LeetCode 162. 寻找峰值(中等)LeetCode 164. 最大间距(中等)LeetCode 165. 比较版本号(中等) LeetCode 160. 相交链表(简单&#…...
关于 Spring Boot 微服务解决方案的对比,并以 Spring Cloud Alibaba 为例,详细说明其核心组件的使用方式、配置及代码示例
以下是关于 Spring Boot 微服务解决方案的对比,并以 Spring Cloud Alibaba 为例,详细说明其核心组件的使用方式、配置及代码示例: 关于 Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案! https://sca.aliyun.com/?spm7145af80…...
3.1多状态专题:LeetCode面试题17.16 按摩师
动态规划解决按摩师预约问题——以LeetCode面试题17.16为例 1.题目链接 LeetCode面试题17.16 按摩师 2.题目描述 一个有名的按摩师收到一系列的预约请求,每个预约都可以选择接受或不接受。但相邻的预约不能同时接受。给定一个包含各预约时长的数组 nums…...
Netty基础入门(一)
1.EventLoopGroup 1、概念 EventLoopGroup 是一组 EventLoop,Channel 一般会调用 EventLoopGroup 的 register 方法来绑定其中一个 EventLoop,后续这个 Channel 上的 io 事件都由此 EventLoop 来处理(保证了 io 事件处理时的线程安全&#x…...
Transformer模型的自注意机制原理、作用、优缺点,通俗易懂
Transformer模型中的自注意力机制(Self - attention Mechanism)可以通俗地理解为一种让模型自动关注文本中不同部分之间关系的方法。 工作原理 假设你有一句话“我正在吃苹果”,自注意力机制会让模型去分析每个词和其他词之间的关联程度。比…...
设计模式-结构型模式-代理模式
概述 代理模式: Proxy Pattern : 是一种结构型设计模式. 它允许你提供一个替代对象来代表真实对象,以此控制对真实对象的访问。 通过代理对象,可以在不改变目标对象的前提下,扩展其功能或控制对其的访问。 简单理解 : 代理模式就是…...
大模型开发:源码分析 Qwen 2.5-VL 视频抽帧模块(附加FFmpeg 性能对比测试)
目录 qwen 视频理解能力 messages 构建 demo qwen 抽帧代码分析 验证两个实际 case 官网介绍图 性能对比:ffmpeg 抽帧、decord 库抽帧 介绍 联系 对比 测试结果 测试明细 ffmpeg 100 qps 测试(CPU) decord 100 qps 测试&#x…...
单调栈 —— 1.基本概念与核心算法
1. 基本概念 1.1 知识预备 在理解单调栈之前,我们需要先掌握两个基础概念:栈(Stack) 和 单调性(Monotonicity)。 什么是栈(Stack) 栈是一种**后进先出(LIFO, Last-In…...
Ollama部署大模型 (完整版本、网速慢处理、聊天界面)
切记!切记!切记! Ollama软件下载的模型一般都是别人微调好的,且模型文件与HuggingFace等平台不一样,使用为主,没有官方API可以对模型微调(教程都是cpp这类的,没必要这么麻烦去操作&a…...
CMake中add_custom_command用法详解
add_custom_command 是 CMake 中用于在构建过程中添加自定义命令的工具。它通常用于生成文件或在构建特定目标前后执行操作。其行为和执行时机取决于具体使用场景。 主要用法 add_custom_command 有两种典型用法: 1. 生成文件(Generating Files&#x…...
基于疾风大模型的新能源储能优化系统:方法、实现与案例分析
一、引言 随着可再生能源渗透率不断提高,储能系统在电力系统中的重要性日益凸显。传统储能控制方法主要基于规则策略和简单优化算法,难以应对高比例新能源场景下的复杂决策需求。本文将详细介绍如何利用疾风大模型(Gale Model)构建智能化的新能源储能优化系统,包含核心方…...
Large Language Model(LLM)的训练和微调
之前一个偏工程向的论文中了,但是当时对工程理论其实不算很了解,就来了解一下 工程流程 横轴叫智能追寻 竖轴上下文优化 Prompt不行的情况下加shot(提示),如果每次都要加提示,就可以试试知识库增强检索来给提示。 如果希望增强…...
Windows 系统中安装 Git 并配置 GitHub 账户
由于电脑重装系统,重新配置了git. 以下是在 Windows 系统中安装 Git 并配置 GitHub 账户的详细步骤: 1. 安装 Git 访问 Git 官网下载页面下载 Windows 版本的 Git 安装程序运行安装程序,使用默认选项即可 2. 配置 Git 用户信息 打开命令…...
KWDB创作者计划—KWDB场景化创新实践:多模态数据融合与边缘智能的突破性应用
引言:AIoT时代的数据库范式重构 在工业物联网设备数量突破千亿、边缘计算节点覆盖率达75%的2025年,传统数据库面临多模态数据处理效率低下、边缘端算力利用率不足、跨域数据协同困难等核心挑战。KWDB(KaiwuDB Community Edition)通…...
波束形成(BF)从算法仿真到工程源码实现-第四节-最小方差无失真响应波束形成(MVDR)
一、概述 本节我们讨论最 小 方 差 无 失 真 响 应 (Minimum Variance Distortionless Response, MVDR)波束形成算法,包括原理分析及代码实现。 更多资料和代码可以进入https://t.zsxq.com/qgmoN ,同时欢迎大家提出宝贵的建议,以共同探讨学习…...
初阶数据结构--链式二叉树
二叉树(链式结构) 前面的文章首先介绍了树的相关概念,阐述了树的存储结构是分为顺序结构和链式结构。其中顺序结构存储的方式叫做堆,并且对堆这个数据结构进行了模拟实现,并进行了相关拓展,接下来会针对链…...
嵌入式硬件篇---单片机周期
文章目录 前言 前言 在单片机中,时序控制是其执行指令和协调外设的核心基础。以下是单片机中常见的各种周期及其详细说明,以层次结构展开: 时钟周期(Clock Cycle) 定义: 时钟周期是单片机的最小时间单位&a…...
嵌入式硬件篇---加法减法积分微分器
文章目录 前言 前言 在模拟电子技术中,加法器、减法器、积分器和微分器是基本的运算电路,通常基于运算放大器(运放)实现。以下是它们的核心原理、典型结构和应用场景: 加法器(Summing Amplifier࿰…...
解决使用VsCode远程ssh连接虚拟机ubuntu需要重复输入密码
1. windows打开windows powershell并输入如下命令 ssh-keygen -t ed25519 -C 你的随意一个邮箱2. 从路径C:\Users\PC.ssh下找到id_ed25519.pub并打开 复制里面全部内容 3. 切换到ubuntu $ cd .ssh/ $ vi authorized_keys 将前一步复制的内容粘贴进去并保存4. vscode重新连接…...
1558 找素数
1558 找素数 ⭐️难度:中等 🌟考点:质数 📖 📚 import java.util.Scanner; import java.util.Arrays;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int a sc.…...
[Android] PDF编辑器 Xodo PDF Reader 9.13.3 (不完全汉化,能用)
[Android] PDF编辑器 Xodo PDF 链接:https://pan.xunlei.com/s/VONeDpxJVwfmeSZu36RvZzSfA1?pwdv67d# 全面的 PDF 查看和批注 支持多种文件格式,包括 PDF 和 Microsoft Office 文档。提供用于添加注释、突出显示文本和为内容添加下划线的工具。包括夜…...
STM32LL库编程系列第八讲——ADC模数转换
系列文章目录 往期文章 STM32LL库编程系列第一讲——Delay精准延时函数(详细,适合新手) STM32LL库编程系列第二讲——蓝牙USART串口通信(步骤详细、原理清晰) STM32LL库编程系列第三讲——USARTDMA通信 STM32LL库编程…...
forms+windows添加激活水印
formswindows添加激活水印 多语言水印文本,根据系统语言自动切换。水印显示在每个屏幕的右下角,位置动态调整。半透明灰色文字,微软雅黑字体。窗口无边框、置顶、透明背景,不干扰用户操作。支持多显示器。高DPI适配。 效果图&am…...
ubuntu 服务器版本网络安全
1. 系统更新与补丁管理 定期更新系统 sudo apt update && sudo apt upgrade -y # 更新所有软件包 sudo apt autoremove # 清理旧内核和依赖启用自动安全更新 修改 /etc/apt/apt.conf.d/50unattended-upgrades,确保安全更新自动安装: Unatt…...
C++之map,set的实现
目录 一、红黑树的修改 1.1、节点结构 1.2、迭代器 1.3、红黑树的结构 二、map的封装 三、set的封装 一、红黑树的修改 首先,我们使用红黑树来封装map和set,其次我们实现的map和set想要复用同一个红黑树,所以我们需要对之…...
Elasticsearch:使用稀疏向量提升相关性
作者:来自 Elastic Vincent Bosc 学习如何在 Elasticsearch 中使用稀疏向量,以最小的复杂性提升相关性并实现搜索结果个性化。 稀疏向量是 ELSER 中的关键组件,但它们的用途远不止于此。在这篇文章中,我们将探讨稀疏向量如何在电商…...
SQL:Normalization(范式化)
目录 Normalization(范式化) 为什么需要 Normalization? 🧩 表格分析: 第一范式(1NF) 什么是第一范式(First Normal Form)? 第二范式(2NF&am…...
在pycharm中搭建yolo11分类检测系统1--PyQt5学习(一)
实验条件:pycharm24.3autodlyolov11环境PyQt5 如果pycharm还没有配PyQt5的话就先去看我原先写的这篇博文: PyQT5安装搭配QT DesignerPycharm)-CSDN博客 跟练参考文章: 目标检测系列(四)利用pyqt5实现yo…...
Neo4j GDS-12-neo4j GDS 库中节点插入(Node Embedding)算法介绍
neo4j GDS 系列 Neo4j APOC-01-图数据库 apoc 插件介绍 Neo4j GDS-01-graph-data-science 图数据科学插件库概览 Neo4j GDS-02-graph-data-science 插件库安装实战笔记 Neo4j GDS-03-graph-data-science 简单聊一聊图数据科学插件库 Neo4j GDS-04-图的中心性分析介绍 Neo…...
【论文阅读】RMA: Rapid Motor Adaptation for Legged Robots
Paper: https://arxiv.org/abs/2107.04034Project: https://ashish-kmr.github.io/rma-legged-robots/Code: https://github.com/antonilo/rl_locomotion训练环境:Raisim 1.方法 RMA(Rapid Motor Adaptation)算法通过两阶段训练实现四足机器…...
C语言数据结构:树的实现、前序、中序、后序遍历
一、什么是树 树是一种非线性的数据结构,由若干个节点组成。每个节点都包含数据,并且可以有多个子节点。树的最顶端是一个特殊的节点,叫根节点,它没有父节点。从根节点开始,树不断向下分叉,形成不同的层次…...
PostgreSQL:逻辑复制与物理复制
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…...
单片机Day05---动态数码管显示01234567
一、原理图 数组索引段码值二进制显示内容00x3f0011 1111010x060000 0110120x5b0101 1011230x4f0100 1111340x660110 0110450x6d0110 1101560x7d0111 1101670x070000 0111780x7f0111 1111890x6f0110 11119100x770111 0111A110x7c0111 1100B120x390011 1001C130x5e0101 1110D140…...
STM32江科大-----SPI
声明:本人跟随b站江科大学习,本文章是观看完视频后的一些个人总结和经验分享,也同时为了方便日后的复习,如果有错误请各位大佬指出,如果对你有帮助可以点个赞小小鼓励一下,本文章建议配合原视频使用❤️ 如…...
OBS SDK 中 ffmpeg_muxer 与 ffmpeg_output 的区别与使用 QSV 编码器的正确方式
在使用 OBS SDK 开发录制或推流功能时,开发者可能会遇到两个看似相似却完全不同的输出类型:ffmpeg_muxer 和 ffmpeg_output。它们的使用方式、编码器支持范围以及配置方式都有显著区别,特别是在使用硬件编码器(如 Intel QSV)时,选择正确的输出类型至关重要。 本文将重点…...
基于AOP+Log4Net+AutoFac日志框架
1.项目概述 这是一个基于 C# 的 WPF 项目 WpfApp12log4net,它综合运用了依赖注入、日志记录和接口实现等多种技术,同时使用了 Autofac、Castle.Core 和 log4net 等第三方库。 2.配置log4net 新建一个Log4Net.config,配置需要记录的日志信息…...
【Hadoop入门】Hadoop生态之Yarn简介
1 什么是Yarn? Yarn(Yet Another Resource Negotiator) 是Hadoop生态系统中的资源管理和调度框架,负责为上层应用提供统一的资源管理和调度服务。 是Hadoop 2.0引入的重要架构改进,成为Hadoop集群的资源管理层…...
猫咪如厕检测与分类识别系统系列【三】融合yolov11目标检测
✅ 前情提要 家里养了三只猫咪,其中一只布偶猫经常出入厕所。但因为平时忙于学业,没法时刻关注牠的行为。我知道猫咪的如厕频率和时长与健康状况密切相关,频繁如厕可能是泌尿问题,停留过久也可能是便秘或不适。为了更科学地了解牠…...
qt的基本使用
先教大家如何基本使用qt,这样是为了后面的服务器使用做铺垫 安装测试用例的创建创建qt界面程序后讲解各文件的作用qt的界面控件实现逻辑功能的流程测试效果 我会写一个测试用例方便大家了解与使用 安装 参考这个文章来安装,链接: qt安装 测试用例的创建…...
Spring AI使用tool Calling和MCP
深入探索 Spring AI Spring AI版本1.0.0.M6 在人工智能与软件开发深度融合的时代,Spring AI 作为一个强大的框架,持续为开发者提供着高效且便捷的工具,以实现与大语言模型(LLM)的无缝交互。Spring AI 的最新版本引入了…...
【前端】webpack一本通
今日更新完毕,不定期补充,建议关注收藏点赞。 目录 简介使用webpack默认只能处理js文件 ->引入加载器对JS语法降级,兼容低版本语法合并文件再次打包进阶 工作原理html-webpack-plugin插件webpack开发服务器引入使用webpack-dev-server模块…...
STM32蓝牙连接Android实现云端数据通信(电机控制-开源)
引言 基于 STM32F103C8T6 最小系统板完成电机控制。这个小项目采用 HAL 库方法实现,通过 CubeMAX 配置相关引脚,步进电机使用 28BYJ-48 (四相五线式步进电机),程序通过蓝牙连接手机 APP 端进行数据收发, OL…...
OpenHarmony Camera开发指导(二):相机设备管理(ArkTS)
在开发一个相机应用前,需要先通过调用Camera接口获取支持的相机设备列表,然后创建相机设备对象做后续处理。 开发步骤 1、导入camera接口,接口中提供了相机相关的属性和方法,导入方法如下。 import { camera } from kit.Camera…...
安卓 手机拨打电话录音保存地址适配
今天来聊一聊各大厂商拨打电话自动录音保存地址适配,希望同学们积极参与评论,把自己的手机型号、Android版本及拨打电话录音地址发一下,众人拾柴火焰高啊,这样有利于后期的同学积累经验,为中国的手机适配做一次贡献。 …...
spring cloud微服务断路器详解及主流断路器框架对比
微服务断路器详解 1. 核心概念 定义:断路器模式通过快速失败机制防止故障扩散,当服务调用出现异常或超时时,自动切换到降级逻辑,避免级联故障。核心功能: 熔断:在故障阈值(如错误率)…...
idea在线离线安装插件教程
概述 对于小白来说,刚使用idea时,还有很多不懂的地方,这里,简单介绍下如何安装插件。让小白能容易上手全盘idea。 1、File -> Settings 2、找到 Plugins -> Marketplace 3、安装 3.1、在线安装 输入想搜索的内容&#x…...
项目管理(高软56)
系列文章目录 项目管理 文章目录 系列文章目录前言一、进度管理二、配置管理三、质量四、风险管理五、真题总结 前言 本节主要讲项目管理知识,这些知识听的有点意思啊。对于技术人想创业,单干的都很有必要听听。 一、进度管理 二、配置管理 三、质量 四…...
通过类似数据蒸馏或主动学习采样的方法,更加高效地学习良品数据分布
好的,我们先聚焦第一个突破点: 通过类似数据蒸馏或主动学习采样的方法,更加高效地学习良品数据分布。 这里我提供一个完整的代码示例: ✅ Masked图像重建 残差热力图 这属于自监督蒸馏方法的一个变体: 使用一个 预…...