C++ 元编程
目录
- C++ 元编程
- 1. 术语
- 2. 元函数
- 1. 数值元函数
- 示例:阶乘计算
- 2. 类型元函数
- 示例:类型选择
- 3. 混合编程
- 1. 常规的计算点积范例
- 2. 混合元编程计算点积
- 4. typelist实现
- 设计和基本操作接口(算法)
- 完整代码
- 5. tuple 实现
- 基础知识
- 1. 左值、右值、左值引用、右值引用
- 2. std::move 究竟做了什么
- 3. std::forward 究竟做了什么
- 4. 万能引用(转发引用)
- 5. 完美转发
- tuple 实现示例
C++ 元编程
元编程的主要目的在于将各种计算从运行期提前至编译期进行,以实现程序运行时的性能提升。也正因如此,元编程是一种增加程序的编译时间,从而提升程序运行效率的编程技术。
在元编程中,涉及许多与循环相关的代码。传统编程中,循环通常采用 for
、while
等语句实现,这些语句一般针对的是运行期的条件变量;而在元编程中,更多的操作其实是针对类型或常量的。这种循环的实现往往会采用递归的手段,使得编译器能够在编译期间完成某些计算。
1. 术语
元编程的英文名称是 Meta Programming,有时也称为 模板元编程(Template Metaprogramming)。可以理解为一种编程手法,用于实现一些比较特殊的功能。元编程与“递归”这一概念紧密相连,代表着在元编程中,大多数情况下都会使用递归编程技术。
模板编程主要应用在泛型编程和元编程:
泛型编程(Generic Programming)强调的是“通用”的概念,旨在通过抽象和参数化来实现代码的复用与灵活性。在泛型编程中,程序员可以编写与类型无关的算法和数据结构,使得同一段代码能够适用于多种类型。模板的设计初衷正是为了满足这一需求。
元编程(Meta Programming)则是一种更高级的编程技巧,旨在通过编译期间的计算和推导来实现某些功能。元编程允许程序员在编译期进行复杂的逻辑处理,通常这些逻辑在运行时才能完成。
2. 元函数
传统的函数都是在程序运行期间被调用和执行的函数,而元函数是能在程序编译期间被调用和执行的函数(编译期间就能得到结果)。引入元函数概念的目的是支持元编程,而元编程的核心也正是元函数。
1. 数值元函数
数值元函数是在编译期间对数值进行计算的元函数。这类元函数可以接收整型常量作为模板参数,并根据这些常量进行编译时计算。数值元函数通常用于实现一些数学运算,如阶乘、斐波那契数列等。
示例:阶乘计算
template<int N>
struct Factorial {static const int value = N * Factorial<N - 1>::value;
};template<>
struct Factorial<0> {static const int value = 1;
};// 使用
constexpr int fact5 = Factorial<5>::value; // fact5 的值为 120
std::cout << fact5 << std::endl; // 输出 120
2. 类型元函数
类型元函数则是针对类型进行操作的元函数。它们允许程序员在编译期间对类型进行推导、选择和变换。这类元函数非常适合于类型特征提取和类型转换等场景。
示例:类型选择
template<bool Condition, typename TrueType, typename FalseType>
struct Conditional;template<typename TrueType, typename FalseType>
struct Conditional<true, TrueType, FalseType> {using type = TrueType;
};template<typename TrueType, typename FalseType>
struct Conditional<false, TrueType, FalseType> {using type = FalseType;
};// 使用
using ResultType = Conditional<true, int, double>::type; // ResultType 的类型为 int
3. 混合编程
混合编程是结合了运行时和编译时计算的技术,允许程序员在编译期间进行一些运算,同时时间复杂度也得到优化。混合编程的关键在于利用模板和递归来处理类型和数值,使得某些操作可以在编译期完成,从而提高运行时性能。
1. 常规的计算点积范例
混合元编程方面,一个比较典型的案例是计算两个向量(数组)点积。
(1)数组a有3个元素a[0]、a[1]、a[2],值分别为1、2、3;
(2)数组b有3个元素b[0]、b[1]、b[2],值分别为4、5、6;
(3)a和b的点积是一个数值,结果为a[0]×b[0] + a[1] ×b[1] + a[2] ×b[2] =1×4+2×5+3×6=32。
在传统编程中,计算两个数组(向量)的点积通常使用循环结构,如for
或while
。以下是一个简单的点积计算示例:
#include <iostream>template<typename T, int U>
auto DotProduct(T* array1, T* array2)
{T dpresult = T{};for (int i = 0; i < U; ++i){dpresult += array1[i] * array2[i];}return dpresult;
}int main()
{int a[] = { 1,2,3 };int b[] = { 4,5,6 };int result = DotProduct<int, 3>(a, b);std::cout << result << std::endl; // 输出 32return 0;
}
2. 混合元编程计算点积
通过元编程,可以在编译期间计算点积。下面的代码展示了如何使用模板和递归实现这一点:
#include <iostream>//泛化版本
template<typename T, int U> //T:元素类型,U:数组大小
struct DotProduct
{static T result(const T* a, const T* b){return (*a) * (*b) +DotProduct<T, U - 1>::result(a + 1, b + 1);}
};
//特化版本,作为递归调用的出口
template<typename T>
struct DotProduct<T, 0>
{static T result(const T *,const T*){return T{};}
};int main()
{int a[] = { 1,2,3 };int b[] = { 4,5,6 };int result = DotProduct<int, 3>::result(a, b);std::cout << result << std::endl;return 0;
}
- 泛化版本:
DotProduct
是一个模板类,它接受元素类型T
和数组大小U
作为模板参数。result
函数是一个静态成员函数,通过递归调用来计算点积。它取当前元素*a
和*b
的乘积,并加上对下一个元素的递归调用。
- 特化版本:
- 当
U
为0
时,递归调用的出口到达。此时返回一个默认初始化的值T{}
,表示点积计算的结束。
- 当
4. typelist实现
typelist的解释为:用来操作一大堆类型的C++容器,就像C++标准库中的list容器能够为数值提供各种基本操作一样(只不过这里操作的不是数值,而是类型)。
从实现上来讲,typelist是一个类模板,译为“类型列表”,这个类模板用来表示一个列表,这个列表中存放着一堆类型。
设计和基本操作接口(算法)
Typelist 的基本定义
template<typename... Types>
struct TypeList {};// 基本类型操作
using EmptyTypeList = TypeList<>; // 空类型列表
1. 取得typelist中的第1个元素(front)
这个操作返回 typelist
中的第一个类型。通过模板特化,可以在编译时获取到这个类型。该操作通常用于获取类型链的起始类型,以便后续处理。
template<typename TList>
struct Front;template<typename Head, typename... Tail>
struct Front<TypeList<Head, Tail...>> {using type = Head; // 返回第一个元素
};
2. 取得typelist容器中元素的数量(size)
这个操作计算并返回 typelist
中包含的类型数量。它使用可变参数模板的特性,通过 sizeof...
来计算类型的数量。
template<typename TList>
struct Size;template<typename... Types>
struct Size<TypeList<Types...>> {static const size_t value = sizeof...(Types); // 元素计数
};
3. 从typelist中移除第1个元素(pop_front)
此操作会返回一个新的 typelist
,该列表中不再包含第一个类型。它通过递归去掉开头的类型,为后续操作提供了简化的列表。
template<typename TList>
struct PopFront;template<typename Head, typename... Tail>
struct PopFront<TypeList<Head, Tail...>> {using type = TypeList<Tail...>; // 移除第一个元素
};
4. 向typelist的开头和结尾插入一个元素(push_front和push_back)
- push_front: 将新类型插入到
typelist
的开头,产生一个新的typelist
。 - push_back: 将新类型插入到
typelist
的结尾,同样产生一个新的typelist
。
template<typename TList, typename NewType>
struct PushFront;template<typename... Types, typename NewType>
struct PushFront<TypeList<Types...>, NewType> {using type = TypeList<NewType, Types...>; // 插入到开头
};template<typename TList, typename NewType>
struct PushBack;template<typename... Types, typename NewType>
struct PushBack<TypeList<Types...>, NewType> {using type = TypeList<Types..., NewType>; // 插入到结尾
};
5. 替换typelist的开头元素(replace_front)
此操作允许替换 typelist
的第一个类型为一个新的类型,并返回一个新的 typelist
。这对于动态更改类型列表的开头非常有用。
template<typename TList, typename NewType>
struct ReplaceFront;template<typename... Tail, typename NewType>
struct ReplaceFront<TypeList<Tail...>, NewType> {using type = TypeList<NewType, Tail...>; // 替换开头元素
};
6. 判断typelist是否为空(is_empty)
此操作检查 typelist
是否包含任何类型。如果列表为空,返回 true
,否则返回 false
。这是确保操作安全性的重要步骤。
template<typename TList>
struct IsEmpty;template<>
struct IsEmpty<EmptyTypeList> {static const bool value = true; // 空类型列表
};template<typename... Types>
struct IsEmpty<TypeList<Types...>> {static const bool value = false; // 非空类型列表
};
7. 根据索引号查找typelist的某个元素(find)
此操作通过索引查找 typelist
中的特定类型。它使用递归进行索引减小,直到找到目标索引的类型。这使得可以根据位置快速访问特定类型。
template<typename TList, size_t Index>
struct Find;template<typename Head, typename... Tail>
struct Find<TypeList<Head, Tail...>, 0> {using type = Head; // 找到第一个元素
};template<typename Head, typename... Tail, size_t Index>
struct Find<TypeList<Head, Tail...>, Index> {using type = typename Find<TypeList<Tail...>, Index - 1>::type; // 递归查找下一个元素
};
8. 遍历typelist找到sizeof值最大的元素(get_maxsize_type)
该操作遍历 typelist
中的所有类型,并返回 sizeof
值最大的类型。它利用条件选择,递归比较每个类型的大小,确定最大值。这在需要根据类型大小进行处理时非常有用。
template<typename TList>
struct GetMaxSizeType;template<typename Head, typename... Tail>
struct GetMaxSizeType<TypeList<Head, Tail...>> {using type = typename std::conditional<(sizeof(Head) >= sizeof(typename GetMaxSizeType<TypeList<Tail...>>::type)),Head,typename GetMaxSizeType<TypeList<Tail...>>::type>::type; // 使用 std::conditional 比较
};// 特化版本,处理空类型列表
template<>
struct GetMaxSizeType<EmptyTypeList> {using type = void; // 空类型列表没有最大类型
};
完整代码
#include <iostream>
#include <type_traits>template<typename... Types>
struct TypeList {};using EmptyTypeList = TypeList<>;// 取得第一个元素
template<typename TList>
struct Front;template<typename Head, typename... Tail>
struct Front<TypeList<Head, Tail...>> {using type = Head;
};// 取得元素数量
template<typename TList>
struct Size;template<typename... Types>
struct Size<TypeList<Types...>> {static const size_t value = sizeof...(Types);
};// 移除第一个元素
template<typename TList>
struct PopFront;template<typename Head, typename... Tail>
struct PopFront<TypeList<Head, Tail...>> {using type = TypeList<Tail...>;
};// 向开头插入一个元素
template<typename TList, typename NewType>
struct PushFront;template<typename... Types, typename NewType>
struct PushFront<TypeList<Types...>, NewType> {using type = TypeList<NewType, Types...>;
};// 向结尾插入一个元素
template<typename TList, typename NewType>
struct PushBack;template<typename... Types, typename NewType>
struct PushBack<TypeList<Types...>, NewType> {using type = TypeList<Types..., NewType>;
};// 替换开头元素
template<typename TList, typename NewType>
struct ReplaceFront;template<typename... Tail, typename NewType>
struct ReplaceFront<TypeList<Tail...>, NewType> {using type = TypeList<NewType, Tail...>;
};// 判断是否为空
template<typename TList>
struct IsEmpty;template<>
struct IsEmpty<EmptyTypeList> {static const bool value = true;
};template<typename... Types>
struct IsEmpty<TypeList<Types...>> {static const bool value = false;
};// 根据索引查找元素
template<typename TList, size_t Index>
struct Find;template<typename Head, typename... Tail>
struct Find<TypeList<Head, Tail...>, 0> {using type = Head; // 找到第一个元素
};template<typename Head, typename... Tail, size_t Index>
struct Find<TypeList<Head, Tail...>, Index> {using type = typename Find<TypeList<Tail...>, Index - 1>::type; // 递归查找下一个元素
};// 遍历找到最大 sizeof 的类型
template<typename TList>
struct GetMaxSizeType;template<typename Head, typename... Tail>
struct GetMaxSizeType<TypeList<Head, Tail...>> {using type = typename std::conditional<(sizeof(Head) >= sizeof(typename GetMaxSizeType<TypeList<Tail...>>::type)),Head,typename GetMaxSizeType<TypeList<Tail...>>::type>::type; // 使用 std::conditional 比较
};// 特化版本,处理空类型列表
template<>
struct GetMaxSizeType<EmptyTypeList> {using type = void; // 空类型列表没有最大类型
};// 测试
int main() {using MyTypes = TypeList<int, double, char>;std::cout << "Size: " << Size<MyTypes>::value << std::endl; // 输出 3std::cout << "Is empty: " << IsEmpty<MyTypes>::value << std::endl; // 输出 0std::cout << "First element type: " << typeid(Front<MyTypes>::type).name() << std::endl; // 输出 intusing Popped = typename PopFront<MyTypes>::type;std::cout << "Size after pop: " << Size<Popped>::value << std::endl; // 输出 2using PushedFront = typename PushFront<MyTypes, float>::type;std::cout << "Size after push front: " << Size<PushedFront>::value << std::endl; // 输出 4using PushedBack = typename PushBack<MyTypes, long>::type;std::cout << "Size after push back: " << Size<PushedBack>::value << std::endl; // 输出 4using FoundType = typename Find<MyTypes, 1>::type; // 查找索引1的类型std::cout << "Found type at index 1: " << typeid(FoundType).name() << std::endl; // 输出 doubleusing MaxSizeType = typename GetMaxSizeType<MyTypes>::type; // 查找最大 sizeof 的类型std::cout << "Max size type: " << typeid(MaxSizeType).name() << std::endl; // 输出 doublereturn 0;
}
- TypeList: 用于存储类型的模板类。
- 基本操作: 提供了如获取第一个元素、计算大小、移除元素、插入元素、替换元素和判断是否为空等基本操作。
Find
: 通过递归查找指定索引的类型。GetMaxSizeType
: 通过比较各类型的sizeof
值,找出最大类型。- 使用示例: 在
main
函数中演示了如何使用这些操作。
5. tuple 实现
基础知识
1. 左值、右值、左值引用、右值引用
-
左值和右值:
- 左值 (lvalue): 表示一个可以被取地址的对象,具有持久的内存位置。例子:
int i = 10;
这里的i
是左值。 - 右值 (rvalue): 表示一个临时的对象,通常是不能取地址的,存在于表达式的右边。例子:
10
是右值。
- 左值 (lvalue): 表示一个可以被取地址的对象,具有持久的内存位置。例子:
-
左值引用:
- 通过左值引用 (
&
) 可以引用一个左值。例子:int &j = i; // j 是左值引用
- 左值引用只能绑定到左值上。尝试将右值绑定到左值引用会导致编译错误,但
const
左值引用可以绑定到右值:const int &j = 10; // 合法
- 通过左值引用 (
-
右值引用:
- 右值引用使用
&&
进行声明,允许绑定到右值。 - 例如:
int &&k = 10; // k 是右值引用
- 右值引用只能绑定到右值。尝试将左值绑定到右值引用会导致编译错误。
- 右值引用使用
-
普通变量:
- 普通的变量(如
int m;
)既不是左值引用也不是右值引用,因为引用必须带有&
或&&
修饰符。
- 普通的变量(如
2. std::move 究竟做了什么
-
std::move
是一个标准库函数,它将左值转换为右值,从而允许使用右值引用。例如:int &&k = std::move(i); // 将左值 i 转换为右值
-
重要的是,
std::move
不会执行任何移动操作,它只是一种类型转换,标记一个对象可以被“移动”。
3. std::forward 究竟做了什么
-
std::forward
是用于实现完美转发的工具,它允许保持参数的值类别(lvalue 或 rvalue)。在模板中使用时,可以根据传入的参数类型决定是保持为左值还是右值。template<typename T> void func(T&& arg) {// 完美转发process(std::forward<T>(arg)); }
4. 万能引用(转发引用)
- 万能引用是指在模板参数中使用的引用类型,可以绑定到左值或右值(例如
T&&
,其中 T 是模板参数)。这种引用在模板中被称为转发引用。
5. 完美转发
- 完美转发使得函数可以根据实际传入的参数类型选择合适的引用类型,从而避免不必要的复制和保证性能。例如,结合
std::forward
和万能引用,可以实现完美转发。
tuple 实现示例
C++ 标准库中的 std::tuple
是一个可以存储不同类型的元素的容器,以下是一个简单的自定义 tuple
实现示例:
tuple
是一种灵活的数据结构,能够存储不同类型的元素。理解左值、右值及其引用非常重要,因为tuple
的实现涉及到对象的生命周期管理、内存效率以及函数调用方式(如移动语义和转发)。std::move
和std::forward
是实现高效代码的重要工具,特别是在模板编程和泛型编程中。
#include <iostream>
#include <utility>
#include <type_traits>template<typename... Types>
class MyTuple;// 特化基础情况
template<>
class MyTuple<> {};// 递归定义
template<typename Head, typename... Tail>
class MyTuple<Head, Tail...> : private MyTuple<Tail...> {
public:Head head; // 当前元素using MyTuple<Tail...>::head; // 继承下一层的头部元素MyTuple(Head h, Tail... t): head(h), MyTuple<Tail...>(t...) {} // 构造函数
};// 获取元素
template<size_t Index, typename Tuple>
struct TupleElement;template<typename Head, typename... Tail>
struct TupleElement<0, MyTuple<Head, Tail...>> {using type = Head; // 返回当前头部元素
};template<size_t Index, typename Head, typename... Tail>
struct TupleElement<Index, MyTuple<Head, Tail...>> {using type = typename TupleElement<Index - 1, MyTuple<Tail...>>::type; // 递归获取
};// 获取元素的辅助函数
template<size_t Index, typename... Types>
typename TupleElement<Index, MyTuple<Types...>>::type& get(MyTuple<Types...>& tuple) {return static_cast<typename TupleElement<Index, MyTuple<Types...>>::type&>(tuple);
}int main() {MyTuple<int, double, char> myTuple(1, 2.5, 'c');std::cout << "First element: " << get<0>(myTuple) << std::endl; // 输出 1std::cout << "Second element: " << get<1>(myTuple) << std::endl; // 输出 2.5std::cout << "Third element: " << get<2>(myTuple) << std::endl; // 输出 creturn 0;
}
相关文章:

C++ 元编程
目录 C 元编程1. 术语2. 元函数1. 数值元函数示例:阶乘计算 2. 类型元函数示例:类型选择 3. 混合编程1. 常规的计算点积范例2. 混合元编程计算点积 4. typelist实现设计和基本操作接口(算法)完整代码 5. tuple 实现基础知识1. 左值…...

运行npm install 时,卡在sill idealTree buildDeps没有反应
一直停留在sill idealTree buildDeps 解决方法 npm config set registry https://registry.npm.taobao.org 配置后用下面命令看是否配置成功 npm config get registry 如果配置还不好使 就执行下行的ssl npm set strict-ssl false 然后执行 npm install 成功执行...

swc 编译 es6为commonjs
如果直接写es6后运行node index.js 报错:SyntaxError: Cannot use import statement outside a module js 我们这里使用swc来将es6编译成CommonJS。 以后可以作为一个简单的框架模版使用。 安装 pnpm add swc/cli swc/core 配置.swcrc {"$schema": &q…...

#nginx配置案例
示例配置 1:反向代理 负载均衡 缓存控制 http {# 定义后端服务器池,用于负载均衡upstream backend_servers {server backend1.example.com weight3; # 权重为3server backend2.example.com weight1; # 权重为1server backend3.example.com backup; …...

STM32—I2C通信外设
1.I2C外设简介 STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担支持多主机模型(可变多主机)支持7位/10位地址模式(11110......)支持不同的通…...

Java-测试-Mockito 入门篇
之前很长一段时间我都认为测试就是使用SpringBootTest类似下面的写法: SpringBootTest class SysAuthServiceTest {AutowiredSysRoleAuthMapper sysRoleAuthMapper;Testpublic void test() {QueryWrapper<SysRoleAuth> queryWrapper new QueryWrapper<&g…...

【jupyter notebook】环境部署及pycharm连接虚拟机和本地两种方式
Python数据处理分析简介 Python作为当下最为流行的编程语言之一 可以独立完成数据分析的各种任务数据分析领域里有海量开源库机器学习/深度学习领域最热门的编程语言在爬虫,Web开发等领域均有应用 与Excel,PowerBI,Tableau等软件比较 Excel有…...

TypeScript异常处理
1.异常的概念 程序运行中意外发生的情况就成为异常 例子: //除法运算function chu(num1:number,num2:number){if(num20){//throw 抛出异常throw new Error(除数不能为零)}let num:numbernum1/num2console.log(num) }//程序出现异常后会停止运行// 捕获异常try{ /…...

go的学习笔记
中文标准库文档:https://studygolang.com/pkgdoc 第一段代码 所有代码的主文件都是main.go,下面的代码直接在项目里面创建main.go运行 package main // 声明文件所在的包,每个go文件必须有归属的包import "fmt" // 引入程序需要的包,为了使用包下的函数,比如Print…...

卷积和转置卷积的输出尺寸计算
卷积和转置卷积的输出尺寸计算 卷积 h是输出的高,h是输入的高,k_h是卷积核的高 w类似stride1 h h - k_h padding*2 1通用公式 stride1就是上面的公式 h (h - k_w 2*padding stride)//stride 一些常见的卷积 高宽不变的卷积:kernel…...

vue3+ts 使用amCharts展示地图,1.点击左侧国家,可以高亮并放大右侧地图对应的国家。 2.展示数据球。
效果图展示: 1.点击左侧国家,可以高亮并放大右侧地图对应的国家。 2.展示数据球。 下载依赖 yarn add amcharts/amcharts5其中,props.countryData的数据格式为 [{ “country”: “加拿大”, “code”: “CA”, “deviceCount”: 1 },{ “c…...

汽车无钥匙启动功能工作原理
移动管家无钥匙启动是一种科技化的汽车启动方式,它允许车主在不使用传统钥匙的情况下启动车辆。这种技术通过智能感应系统实现,车主只需携带智能钥匙,当靠近车辆时,车辆能够自动解锁并准备启动。启动车辆时,车主无…...

C++标准的一些特性记录:C++11的auto和decltype
文章目录 auto容器遍历配合lambda表达式decltype两者对引用类型的处理是相同的decltype保留const,而auto不会保留const在C++11中,引入了两个新的关键字,auto和decltype两个关键字,都是用于做类型推断。但是使用的场景有些区别。 auto 容器遍历 auto这个关键字,我个人在编…...

【Elasticsearch系列四】ELK Stack
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

【新手上路】衡石分析平台使用手册-认证方式
认证方式 用户登录衡石系统时,系统需要对输入的用户名和密码进行验证,保证系统的安全。衡石提供 CAS、SAML2、OAUTH2等多种单点登录认证方式。在 SSO 单点登录中,衡石是服务提供者 SP(Service Provider)为用户提供所…...

数字电路与逻辑设计-触发器功能测试及其应用
一、实验目的 1.验证基本RS、JK、D、T和T’触发器的逻辑功能及使用方法; 2.能进行触发器之间的相互转换; 3.学习触发器的一些应用。 二、实验原理 触发器具有两个能够自行保持的稳定状态,用以表示逻辑状…...

【网站架构部署与优化】web服务与http协议
文章目录 HTMLHTML 概述HTML 语法规则HTML 文件结构头标签中常用标签静态网页与动态网页1. 静态网页2. 动态网页3. 动态网页语言 HTTP协议概述主要的HTTP版本包括:HTTP方法GET与POST方法的比较 HTTP状态码分类及常见状态码HTTP常见状态码 HTTP 请求流程分析1. 请求报…...

【字符函数】strcpy函数(字符串复制函数)+strcat函数(字符串追加)+strcmp函数(字符串比较)【笔记】
1.复制函数--------------strcpy函数 函数使用 char*strcpy(char* destination, const char* source) strcpy函数用于拷贝字符串,即将一个字符串中的内容拷贝到另一个字符串中(会覆盖原字符串内容)。它的参数是两个指…...

codetop字符串刷题,刷穿地心!!不再畏惧!!暴打面试官!!
主要供自己回顾与复习,题源codetop标签字符串近半年,会不断更新 1.有效的括号字符串2.括号生成3.最长单词4.字符串转换整数(atoi)5.整数转罗马数字6.罗马数字转整数7.比较版本号8.最长公共前缀9.面试题17.15.最长单词10.验证IP地址11.面试题01.06.字符串…...

快速体验Linux发行版:DistroSea详解与操作指南
DistroSea 是一个功能强大的在线平台,允许用户在无需下载或安装的情况下,通过浏览器直接测试多种Linux和BSD发行版。该平台非常适合Linux爱好者、系统管理员和开发者,提供一个简便的方式来体验各种操作系统而无需影响本地设备。 为什么选择D…...

Java设计模式—面向对象设计原则(二) --------> 里氏代换原则 LSP (完整详解,附有代码+案列)
文章目录 里氏代换原则3.2.1 概述3.2.2 改进上述代码 里氏代换原则 里氏代换原则:Liskov Substitution Principle,LSP 3.2.1 概述 里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则:任何基类可以出现的地方,子类一定…...

使用ShardingSphere实现MySql的分库分表
目录 一 什么是ShardingSphere分库分表 二 代码实现 1.导入相关依赖 2.配置相关参数 3.创建学生类以及mapper接口 4.实现 StandardShardingAlgorithm接口自定义分片算法 唐洋洋我知道你在看!!!嘿嘿 一 什么是ShardingSphere分库分表 我们平时在设计数据库的时候…...

为什么 Feign 要用 HTTP 而不是 RPC?
一、引言 在现代微服务架构中,服务之间的通信是至关重要的环节。Feign 是一种常用的声明式 HTTP 客户端工具,它简化了服务间的调用过程。然而,在服务通信的领域中,除了基于 HTTP 的方式,还有 RPC(Remote Pr…...

OJ在线评测系统 前端开发设计优化通用菜单组件二 调试用户自动登录
通用的菜单组件开发二 接下来要完善 权限功能 就是只有登录后才能进入题目查看界面 用户只能看到我们有权限的菜单 我们要在路由文件里面去操作 原理是控制路由设置隐藏 只要用户没有权限 就过滤掉隐藏 全局权限管理 实现想清楚有那些权限 /*** 权限定义*/ const ACCES…...

mongodb 安装教程
mongodb 安装教程: https://blog.51cto.com/u_13646338/5449015 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-5.0.9.tgz tar -zxvf mongodb-linux-x86_64-rhel70-5.0.9.tgz -C /opt/module/ [roothadoop102 module]# mv mongodb-linux-…...

切换淘宝最新镜像源npm
要切换淘宝的npm镜像源,可以按照以下步骤进行: 1. 打开命令行工具(如Terminal、CMD等)。 2. 输入以下命令来查看当前的npm镜像源: npm config get registry 3. 如果当前的镜像源不是淘宝镜像源ÿ…...

SpringAI-基于java大模型的胡言乱语
最近看了一点相关的springAI知识,做个小总结 胡言乱语开始 1.不同的ai调用api一般单独汇总成一个依赖,比如说调用openai的api的依赖是spring-ai-openai-spring-boot-starter。 2.最常用的展示方式是流式对话,AI的数据是一个字一个字生成的…...

python提问及解析
在看答案之前,可以先试试自己做哦! 1.图书馆借书还书系统 问题描述 问题:设计一个Python程序,该程序模拟一个大型图书馆的图书管理系统。图书馆拥有成千上万的书籍,每本书都有一个唯一的ISBN号、书名、作者、出版年份…...

从Apple Intelligence到IoT Intelligence,端侧生成式AI时代加速到来
9月10日凌晨1点,苹果新品发布会如期举行,全新iPhone16系列成为苹果生态中真正意义上的第一款原生AI手机,在第二代3nm工艺A18和A18 Pro芯片的加持下,iPhone16系列能够容纳并快速运行以Apple Intelligence为中心的生成式AI功能在手机…...

智能AC管理系统HTTPD-AC 1.0服务存在未授权访问漏洞
@[toc] 智能AC管理系统HTTPD-AC 1.0服务存在未授权访问漏洞 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途…...