C++泛型编程指南09 类模板实现和使用友元

文章目录

      • 第2章 类模板 `Stack` 的实现
        • 2.1 类模板 `Stack` 的实现 (Implementation of Class Template Stack)
        • 2.1.1 声明类模板 (Declaration of Class Templates)
        • 2.1.2 成员函数实现 (Implementation of Member Functions)
      • 2.2 使用类模板 `Stack`
      • 脚注
      • 改进后的叙述总结
      • 脚注
      • 2.3 类模板的局部使用 (Partial Usage of Class Templates)
        • 2.3.1 Concepts
      • 参考附件E关于更多的有关C++ Concept的讨论
      • 改进后的叙述总结
        • 2.3 类模板的局部使用
        • 2.3.1 Concepts
      • 2.4 友元 (Friends)
        • 选项1:隐式地定义一个新的函数模板
        • 选项2:前向声明 `Stack<T>` 的输出操作为模板
      • 改进后的叙述总结
        • 2.4 友元 (Friends)
        • 选项1:隐式定义新的函数模板
        • 选项2:前向声明输出操作符为模板
      • 脚注

第2章 类模板 Stack 的实现

2.1 类模板 Stack 的实现 (Implementation of Class Template Stack)

正如函数模板,类模板可以在一个头文件中声明和定义。以下是一个简单的 Stack 类模板的实现示例:

// basics/stack1.hpp#include <vector>
#include <cassert>template <typename T>
class Stack {
private:std::vector<T> elems;  // 元素存储在向量中public:void push(T const& elem);  // 压入元素void pop();  // 弹出元素T const& top() const;  // 返回栈顶元素bool empty() const {  // 检查栈是否为空return elems.empty();}
};template <typename T>
void Stack<T>::push(T const& elem) {elems.push_back(elem);  // 将元素添加到向量末尾
}template <typename T>
void Stack<T>::pop() {assert(!elems.empty());elems.pop_back();  // 移除向量中的最后一个元素
}template <typename T>
T const& Stack<T>::top() const {assert(!elems.empty());return elems.back();  // 返回向量中的最后一个元素
}

该类模板使用C++标准库中的 std::vector 来管理元素,从而避免了手动处理内存管理和拷贝控制等复杂问题,使我们可以专注于类模板接口的设计。

2.1.1 声明类模板 (Declaration of Class Templates)

声明类模板与声明函数模板类似:在声明之前,必须声明一个或多个类型参数的标识符。常见的标识符是 T

template <typename T>
class Stack {...
};

关键字 typename 也可以用 class 替代:

template <class T>
class Stack {...
};

在类模板中,T 可以像其他任何类型一样用于声明成员变量和成员函数。在这个例子中,T 被用于声明一个 std::vector<T> 成员变量 elems,并在成员函数 push() 中作为参数类型,在 top() 函数中作为返回类型。

template <typename T>
class Stack {
private:std::vector<T> elems;  // 元素public:void push(T const& elem);  // 压入元素void pop();  // 弹出元素T const& top() const;  // 返回栈顶元素bool empty() const {  // 检查栈是否为空return elems.empty();}
};

在类模板内部,直接使用类名(如 Stack)表示带有当前模板参数的类。例如,如果需要声明构造函数和赋值运算符,通常会这样写:

template <typename T>
class Stack {...Stack(Stack const&);  // 拷贝构造函数Stack& operator=(Stack const&);  // 赋值运算符
};

这与显式指定模板参数的形式等价:

template <typename T>
class Stack {...Stack(Stack<T> const&);  // 拷贝构造函数Stack<T>& operator=(Stack<T> const&);  // 赋值运算符
};

但在类模板内部,第一种形式更为简洁且常用。

然而,在类模板外部定义成员函数时,必须明确指定模板参数:

template <typename T>
bool operator==(Stack<T> const& lhs, Stack<T> const& rhs);

在需要类名而不是具体类型的地方,可以直接使用 Stack。特别是在构造函数和析构函数名称的情况下。

与非模板类不同,类模板不能在函数内部或块作用域内声明。它们通常只能定义在全局作用域、命名空间作用域或类声明内。

2.1.2 成员函数实现 (Implementation of Member Functions)

定义类模板的成员函数时,必须指定这是一个模板,并且必须使用类模板的完整类型限定。例如,Stack 类的 push() 成员函数的实现如下:

template <typename T>
void Stack<T>::push(T const& elem) {elems.push_back(elem);  // 将元素添加到向量末尾
}

在这种情况下,elems 是一个 std::vector<T> 对象,push_back() 方法将元素添加到向量的末尾。

需要注意的是,std::vectorpop_back() 方法移除最后一个元素但不返回它,这是为了保证异常安全性。完全异常安全的 pop() 版本无法同时返回被移除的元素。然而,如果我们忽略这一限制,可以实现一个返回被移除元素的 pop() 函数:

template <typename T>
T Stack<T>::pop() {assert(!elems.empty());T elem = elems.back();  // 保存最后一个元素elems.pop_back();  // 移除最后一个元素return elem;  // 返回保存的元素
}

由于 back()pop_back() 在空向量上调用会导致未定义行为,因此需要检查栈是否为空。如果为空,则触发断言,因为在空栈上调用 pop() 是错误的。同样的检查也适用于 top() 函数,它返回栈顶元素但不移除它:

template <typename T>
T const& Stack<T>::top() const {assert(!elems.empty());return elems.back();  // 返回最后一个元素
}

当然,对于任何成员函数,也可以在类声明中以内联方式实现:

template <typename T>
class Stack {...void push(T const& elem) {elems.push_back(elem);  // 将元素添加到向量末尾}
};

通过这种方式,我们可以在类声明中直接实现简单的成员函数,从而使代码更加紧凑和易读。

2.2 使用类模板 Stack

在C++17之前,使用类模板时必须显式指定模板实参。以下是一个展示如何使用 Stack<> 类模板的示例:

// basics/stack1test.cpp#include "stack1.hpp"
#include <iostream>
#include <string>int main() {// 创建一个 int 类型的栈Stack<int> intStack;// 创建一个 std::string 类型的栈Stack<std::string> stringStack;// 操作 int 类型的栈intStack.push(7);std::cout << intStack.top() << '\n';  // 输出: 7// 操作 std::string 类型的栈stringStack.push("hello");std::cout << stringStack.top() << '\n';  // 输出: hellostringStack.pop();
}

通过声明 Stack<int>,我们将 int 类型作为类模板中 T 的类型参数。因此,intStack 是一个使用 std::vector<int> 存储元素的对象。任何被调用的成员函数将根据该类型进行实例化。

类似地,通过声明 Stack<std::string>,我们创建了一个使用 std::vector<std::string> 存储元素的对象。任何被调用的成员函数也将根据该类型进行实例化。

关键点:

  • 实例化时机:只有当成员函数被实际调用时,它们才会被实例化。这不仅节省了编译时间和空间,还允许类模板的部分使用。

  • 实例化示例:在这个例子中,int 类型和 std::string 类型的默认构造函数、push() 函数和 top() 函数都将被实例化。然而,pop() 函数仅对 std::string 类型进行了实例化。如果类模板有静态成员,这些静态成员也只会在特定类型的实例化过程中被实例化一次。

实例化后的类模板类型可以像其他类型一样使用,可以用 constvolatile 进行限定,或者基于它衍生出数组和引用。也可以将其作为 typedefusing 进行类型定义的一部分(更多类型定义的内容详见第2.8节),或者在构建其他模板类型时作为类型参数。例如:

void foo(Stack<int> const& s) {  // 参数 s 是 int 类型的 Stackusing IntStack = Stack<int>;  // IntStack 是 Stack<int> 的别名Stack<int> istack[10];        // istack 是长度为 10 的 Stack<int> 数组IntStack istack2[10];         // istack2 也是长度为 10 的 Stack<int> 数组
}Stack<float*> floatPtrStack;      // float 指针的 Stack
Stack<Stack<int>> intStackStack;  // int 类型的 Stack 的 Stack

模板实参可以是任何类型,唯一的要求是任何被调用的操作对该类型都是可行的。

需要注意的是,在C++11之前,必须在两个闭合模板括号之间放置空格,以避免语法错误。例如:

Stack<Stack<int> > intStackStack;  // 在 C++11 之前的正确写法

如果不这样做而使用符号 >>,会导致语法错误:

Stack<Stack<int>> intStackStack;  // 在 C++11 之前会引发错误

旧版本的这种行为的原因是为了帮助C++编译器在词法分析阶段将源代码分割成独立的语义片段(tokenize the source code)。然而,由于缺少空格是个常见的bug,C++11移除了“在两个闭合模板括号中间必须加入空格”的规则,这一改变被称为“角括号hack”。

脚注

C++17引入了类模板实参推断(Class Template Argument Deduction, CTAD),使得在某些情况下可以跳过显式指定模板实参,只要可以从构造函数推断出模板实参。这将在第2.9节中详细讨论。


改进后的叙述总结

在C++17之前,使用类模板时需要显式指定模板实参。以下是使用 Stack<> 类模板的一个示例:

#include "stack1.hpp"
#include <iostream>
#include <string>int main() {// 创建 int 类型的栈Stack<int> intStack;// 创建 std::string 类型的栈Stack<std::string> stringStack;// 操作 int 类型的栈intStack.push(7);std::cout << intStack.top() << '\n';  // 输出: 7// 操作 std::string 类型的栈stringStack.push("hello");std::cout << stringStack.top() << '\n';  // 输出: hellostringStack.pop();
}

通过声明 Stack<int>Stack<std::string>,我们分别创建了存储 intstd::string 类型元素的栈。只有在调用成员函数时,这些函数才会根据具体类型进行实例化。

实例化后的类模板类型可以像其他类型一样使用,可以通过 constvolatile 进行限定,或者基于它衍生出数组和引用。也可以将其作为 typedefusing 进行类型定义的一部分,或者在构建其他模板类型时作为类型参数。例如:

void foo(Stack<int> const& s) {  // 参数 s 是 int 类型的 Stackusing IntStack = Stack<int>;  // IntStack 是 Stack<int> 的别名Stack<int> istack[10];        // istack 是长度为 10 的 Stack<int> 数组IntStack istack2[10];         // istack2 也是长度为 10 的 Stack<int> 数组
}Stack<float*> floatPtrStack;      // float 指针的 Stack
Stack<Stack<int>> intStackStack;  // int 类型的 Stack 的 Stack

在C++11之前,必须在两个闭合模板括号之间放置空格,以避免语法错误:

Stack<Stack<int> > intStackStack;  // 在 C++11 之前的正确写法

不这样做会导致语法错误:

Stack<Stack<int>> intStackStack;  // 在 C++11 之前会引发错误

旧版本的这种行为的原因是为了帮助C++编译器在第一轮中将源代码分成独立语义的片段。然而,由于缺少空格是个典型的bug,C++11移除了“在两个闭合模板括号中间必须加入空格”的规则,称为“角括号hack”。

脚注

C++17引入了类模板实参推断(CTAD),使得可以跳过指定模板实参,只要可以从构造函数推断出模板实参。这将在第2.9节中详细讨论。

2.3 类模板的局部使用 (Partial Usage of Class Templates)

类模板并不强制要求模板实参提供所有可能的操作,而只需要提供必要的操作。以下是一个具体的示例,展示了这一点:

假设 Stack<> 类模板提供了一个成员函数 printOn(),用于打印整个栈的内容,并对每个元素调用 operator<<

template <typename T>
class Stack {...void printOn(std::ostream& strm) const {for (T const& elem : elems) {strm << elem << ' ';  // 每个元素调用 operator<<}}
};

尽管如此,你依然可以使用没有定义 operator<< 的类作为该类模板的模板实参:

Stack<std::pair<int, int>> ps;  // 注意:std::pair<> 没有定义 operator<<
ps.push({4, 5});  // OK
ps.push({6, 7});  // OK
std::cout << ps.top().first << '\n';  // OK
std::cout << ps.top().second << '\n';  // OK

只有当调用这样的栈的 printOn() 方法时,代码才会生成错误,因为它不能实例化对该特殊类型的 operator<< 的调用:

ps.printOn(std::cout);  // ERROR: 元素类型不支持 operator<<
2.3.1 Concepts

为了明确哪些操作是模板实例化所需要的,术语 概念(Concept) 被用来指示约束条件的集合,并在模板库中重复使用。例如,C++ 标准库依赖于随机访问迭代器(random access iterator)和默认构造(default constructible)等概念。

截至 C++17,concepts 主要通过文档或代码注释进行表述。这可能导致未遵循约束条件时产生混乱的错误消息(详见第9.4节)。

自 C++11 起,可以通过使用 static_assert 关键字和预定义的类型特性来检查基本的约束条件,例如:

template <typename T>
class C {static_assert(std::is_default_constructible<T>::value, "Class C requires default-constructible elements");...
};

没有该断言,如果需要默认构造函数,编译依然会失败,但错误信息可能包含整个模板实例化的历史,从开始实例化到真实的模板定义(详见第9.4节)。

对于更复杂的约束条件,如类型 T 的对象是否提供某种特定的成员函数或是否可以使用 < 操作符进行比较,则需要更详细的检查。详见第19.6.3节的一个详细代码示例。

参考附件E关于更多的有关C++ Concept的讨论


改进后的叙述总结

2.3 类模板的局部使用

类模板不需要模板实参提供所有可能的操作,而只需提供必要的操作。例如:

template <typename T>
class Stack {...void printOn(std::ostream& strm) const {for (T const& elem : elems) {strm << elem << ' ';  // 每个元素调用 operator<<}}
};Stack<std::pair<int, int>> ps;  // std::pair<> 没有定义 operator<<
ps.push({4, 5});  // OK
ps.push({6, 7});  // OK
std::cout << ps.top().first << '\n';  // OK
std::cout << ps.top().second << '\n';  // OK// 仅在调用 printOn() 时会报错
ps.printOn(std::cout);  // ERROR: 元素类型不支持 operator<<
2.3.1 Concepts

概念(Concept) 是一组约束条件,用于确保模板实参满足特定要求。例如,C++ 标准库依赖于诸如随机访问迭代器和默认构造等概念。

截至 C++17,这些概念主要通过文档或代码注释描述。自 C++11 起,可以使用 static_assert 和类型特性来检查基本约束条件:

template <typename T>
class C {static_assert(std::is_default_constructible<T>::value, "Class C requires default-constructible elements");...
};

对于更复杂的约束条件,如特定成员函数的存在或 < 操作符的支持,需进一步的检查方法。详见第19.6.3节的详细代码示例。

2.4 友元 (Friends)

除了使用 printOn() 方法来打印栈的内容,使用操作符 << 将是更好的选择。然而,通常操作符 << 都实现为非成员函数,这可以通过内联方式调用 printOn() 方法:

template <typename T>
class Stack {...void printOn(std::ostream& strm) const { ... }friend std::ostream& operator<< (std::ostream& strm, Stack<T> const& s) {s.printOn(strm);return strm;}
};

注意,这意味着类 Stack<> 的操作符 << 不是一个函数模板,而是在必要时由类模板实例化的一个普通函数。

然而,当尝试声明友元函数并在之后定义时,事情会变得复杂。我们有两种主要的选择:

选项1:隐式地定义一个新的函数模板

这需要使用一个不同的模板参数,比如 U

template <typename T>
class Stack {...template <typename U>friend class std::ostream& operator<< (std::ostream&, Stack<U> const&);
};

无论再次使用 T 还是跳过模板参数声明都无法工作(无论是内层 T 屏蔽外层 T 还是在命名空间范围内声明非模板参数)。

选项2:前向声明 Stack<T> 的输出操作为模板

这需要先进行 Stack<T> 的前向声明:

template <typename T>
class Stack;template <typename T>
std::ostream& operator<< (std::ostream&, Stack<T> const&);template <typename T>
class Stack {...friend std::ostream& operator<< <T> (std::ostream&, Stack<T> const&);
};

注意“函数名”即 << 操作后面的 <T>。因此,我们声明了一个非成员函数模板的特化版本作为友元。没有 <T>,我们将声明一个新的非模板函数,详见第12.5.2节。

在任何情形下,依然可以使用没有定义 << 操作的类作为成员。只有调用该 Stack<< 操作才会引发错误:

Stack<std::pair<int, int>> ps;  // std::pair<> 没有定义 << 操作
ps.push({4, 5});  // OK
ps.push({6, 7});  // OK
std::cout << ps.top().first << '\n';  // OK
std::cout << ps.top().second << '\n';  // OK
std::cout << ps << '\n';  // 错误: 元素类型不支持 << 操作

改进后的叙述总结

2.4 友元 (Friends)

为了更好地打印栈的内容,使用操作符 << 是一个更好的选择。通常情况下,操作符 << 实现为非成员函数,并通过内联方式调用 printOn() 方法:

template <typename T>
class Stack {...void printOn(std::ostream& strm) const { ... }friend std::ostream& operator<< (std::ostream& strm, Stack<T> const& s) {s.printOn(strm);return strm;}
};

需要注意的是,这里的 operator<< 不是一个函数模板,而是由类模板实例化生成的一个普通函数。

然而,在声明和定义友元函数时可能会遇到一些复杂性。以下是两种处理方法:

选项1:隐式定义新的函数模板

这种方式需要引入一个新的模板参数,例如 U

template <typename T>
class Stack {...template <typename U>friend class std::ostream& operator<< (std::ostream&, Stack<U> const&);
};

这种方法存在一些问题,例如重新使用 T 或跳过模板参数声明都会导致编译错误。

选项2:前向声明输出操作符为模板

首先进行 Stack<T> 的前向声明:

template <typename T>
class Stack;template <typename T>
std::ostream& operator<< (std::ostream&, Stack<T> const&);template <typename T>
class Stack {...friend std::ostream& operator<< <T> (std::ostream&, Stack<T> const&);
};

注意在 operator<< 后面加上 <T>,这表明我们声明的是一个非成员函数模板的特化版本作为友元。如果省略 <T>,则会声明一个新的非模板函数,详见第12.5.2节。

即使如此,你仍然可以使用没有定义 << 操作的类作为成员。只有在调用 Stack<< 操作时才会引发错误:

Stack<std::pair<int, int>> ps;  // std::pair<> 没有定义 << 操作
ps.push({4, 5});  // OK
ps.push({6, 7});  // OK
std::cout << ps.top().first << '\n';  // OK
std::cout << ps.top().second << '\n';  // OK
std::cout << ps << '\n';  // 错误: 元素类型不支持 << 操作

脚注

这是个模板化实体(templated entity),详见第12.1节。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/12180.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【面经】字节南京一面部分题目记录

南京字节一面题&#xff0c;可能因为项目不太匹配&#xff0c;全程八股比较多&#xff0c;也有两道手撕代码题&#xff0c;强度还是有的。为了方便大家学习&#xff0c;大部分答案由GPT整理&#xff0c;有些题给出了我认为回答比较好的博客链接。 文章目录 一、python2 和 pyth…

【C语言篇】“三子棋”

一、游戏介绍 三子棋&#xff0c;英文名为 Tic - Tac - Toe&#xff0c;是一款简单而经典的棋类游戏。游戏在一个 33 的棋盘上进行&#xff0c;两名玩家轮流在棋盘的空位上放置自己的棋子&#xff08;通常用 * 和 # 表示&#xff09;&#xff0c;率先在横、竖或斜方向上连成三个…

vscode软件操作界面UI布局@各个功能区域划分及其名称称呼

文章目录 abstract检查用户界面的主要区域官方文档关于UI的介绍 abstract 检查 Visual Studio Code 用户界面 - Training | Microsoft Learn 本质上&#xff0c;Visual Studio Code 是一个代码编辑器&#xff0c;其用户界面和布局与许多其他代码编辑器相似。 界面左侧是用于访…

【B站保姆级视频教程:Jetson配置YOLOv11环境(六)PyTorchTorchvision安装】

Jetson配置YOLOv11环境&#xff08;6&#xff09;PyTorch&Torchvision安装 文章目录 1. 安装PyTorch1.1安装依赖项1.2 下载torch wheel 安装包1.3 安装 2. 安装torchvisiion2.1 安装依赖2.2 编译安装torchvision2.2.1 Torchvisiion版本选择2.2.2 下载torchvisiion到Downloa…

于动态规划的启幕之章,借 C++ 笔触绘就算法新篇

注意&#xff1a;代码由易到难 P1216 [IOI 1994] 数字三角形 Number Triangles 题目链接&#xff1a;[IOI 1994] 数字三角形 Number Triangles - 洛谷 题目描述 观察下面的数字金字塔。 写一个程序来查找从最高点到底部任意处结束的路径&#xff0c;使路径经过数字的和最大。每…

分页按钮功能

前言 在前端开发中&#xff0c;分页功能是一个常见的需求&#xff0c;特别是当需要展示大量数据时&#xff0c;它能有效提升用户体验。该文章结合运用了HTML&#xff0c;CSS&#xff0c;JS实现网页的分页按钮功能&#xff0c;并且可以选择每页显示的条数试试更新总页数及显示当…

SAP HCM 回溯分析

最近总有人问回溯问题&#xff0c;今天把12年总结的笔记在这共享下&#xff1a; 12年开这个图的时候总是不明白是什么原理&#xff0c;教程看N次&#xff0c;网上资料找一大堆&#xff0c;就是不明白原理&#xff0c;后来为搞明白逻辑&#xff0c;按照教材的数据一样做&#xf…

gitea - fatal: Authentication failed

文章目录 gitea - fatal: Authentication failed概述run_gitea_on_my_pkm.bat 笔记删除windows凭证管理器中对应的url认证凭证启动gitea服务端的命令行正常用 TortoiseGit 提交代码备注END gitea - fatal: Authentication failed 概述 本地的git归档服务端使用gitea. 原来的用…

X Window System 架构概述

X Window System 架构概述 1. X Server 与 X Client ​ 这里引入一张维基百科的图&#xff0c;在Linux系统中&#xff0c;若用户需要图形化界面&#xff0c;则可以使用X Window System&#xff0c;其使用**Client-Server**架构&#xff0c;并通过网络传输相关信息。 ​ ​ X…

Linux防火墙基础

一、Linux防火墙的状态机制 1.iptables是可以配置有状态的防火墙&#xff0c;其有状态的特点是能够指定并记住发送或者接收信息包所建立的连接状态&#xff0c;其一共有四种状态&#xff0c;分别为established invalid new related。 established:该信息包已建立连接&#x…

[论文学习]Adaptively Perturbed Mirror Descent for Learning in Games

[论文学习]Adaptively Perturbed Mirror Descent for Learning in Games 前言概述前置知识和问题约定单调博弈&#xff08;monotone game&#xff09;Nash均衡和Gap函数文章问题定义Mirror Descent 方法评价 前言 文章链接 我们称集合是紧的&#xff0c;则集合满足&#xff1…

Go学习:类型转换需注意的点 以及 类型别名

目录 1. 类型转换 2. 类型别名 1. 类型转换 在从前的学习中&#xff0c;知道布尔bool类型变量只有两种值true或false&#xff0c;C/C、Python、JAVA等编程语言中&#xff0c;如果将布尔类型bool变量转换为整型int变量&#xff0c;通常采用 “0为假&#xff0c;非0为真”的方…

使用Pygame制作“吃豆人”游戏

本篇博客展示如何使用 Python Pygame 编写一个简易版的“吃豆人&#xff08;Pac-Man&#xff09;” 风格游戏。这里我们暂且命名为 Py-Man。玩家需要控制主角在一个网格地图里移动、吃掉散布在各处的豆子&#xff0c;并躲避在地图中巡逻的幽灵。此示例可帮助你理解网格地图、角…

ubuntu磁盘扩容

ubuntu磁盘扩容 描述先在虚拟机设置里面扩容进入Ubuntu 配置使用命令行工具parted进行分区输出如下完成 描述 执行命令,查看 fs 类型是什么 lsblk -o NAME,FSTYPE,MOUNTPOINT将60G扩容到100G&#xff0c;其中有些操作我也不知道什么意思&#xff0c;反正就是成功了&#xff0…

redis底层数据结构

底层数据结构 了解下这些咱常用的数据其底层实现是啥 在提到使用哪类数据结构之前&#xff0c;先来了解下redis底层到底有多少种数据结构 1&#xff0c;sds动态字符串 概念与由来 redis是一种使用C语言编写的nosql&#xff0c;redis存储的key数据均为string结构&#xff0…

ChatGPT怎么回事?

纯属发现&#xff0c;调侃一下~ 这段时间deepseek不是特别火吗&#xff0c;尤其是它的推理功能&#xff0c;突发奇想&#xff0c;想用deepseek回答一些问题&#xff0c;回答一个问题之后就回复服务器繁忙&#xff08;估计还在被攻击吧~_~&#xff09; 然后就转向了GPT&#xf…

趣味Python100例初学者练习01

1. 1 抓交通肇事犯 一辆卡车违反交通规则&#xff0c;撞人后逃跑。现场有三人目击该事件&#xff0c;但都没有记住车号&#xff0c;只记下了车号的一些特征。甲说&#xff1a;牌照的前两位数字是相同的&#xff1b;乙说&#xff1a;牌照的后两位数字是相同的&#xff0c;但与前…

2024-我的学习成长之路

因为热爱&#xff0c;无畏山海

蓝桥杯备考:高精度算法之除法

我们除法的高精度其实也不完全是高精度&#xff0c;而是一个高精度作被除数除以一个低精度 模拟我们的小学除法 由于题目中我们的除数最大是1e9&#xff0c;当它真正是1e9的时候&#xff0c;t是有可能超过1e9的&#xff0c;所以要用long long

Maven jar 包下载失败问题处理

Maven jar 包下载失败问题处理 1.配置好国内的Maven源2.重新下载3. 其他问题 1.配置好国内的Maven源 打开⾃⼰的 Idea 检测 Maven 的配置是否正确&#xff0c;正确的配置如下图所示&#xff1a; 检查项⼀共有两个&#xff1a; 确认右边的两个勾已经选中&#xff0c;如果没有请…