现代C++16 pair

news/2024/12/12 1:17:45/

文章目录

      • 1. **概述**
      • 2. **成员类型和成员对象**
      • 3. **构造函数**
      • 4. **成员函数**
      • 5. **非成员函数**
        • 5.1 **`make_pair`**
        • 5.2 **比较运算符**
        • 5.3 **`std::swap`**
        • 5.4 **`std::get`**
      • 6. **辅助类**
        • 6.1 **`std::tuple_size` 和 `std::tuple_element`**
        • 6.2 **`std::common_type` 和 `std::basic_common_reference`**
        • 6.3 **`std::formatter`**
      • 7. **析构函数**
      • 8. **示例代码**
      • 9. **总结**
      • 1. **`std::pair` 与 `std::tuple` 的集成**
        • 示例:将 `std::pair` 转换为 `std::tuple`
        • 输出:
        • 示例:将 `std::tuple` 转换为 `std::pair`
        • 输出:
      • 2. **`std::pair` 与 `std::map` 的集成**
        • 示例:使用 `std::pair` 插入和访问 `std::map` 中的元素
        • 输出:
        • 解释:
      • 3. **`std::pair` 与 `std::set` 的集成**
        • 示例:使用 `std::pair` 存储多个属性的唯一组合
        • 输出:
        • 解释:
        • 自定义排序规则
        • 输出:
        • 解释:
      • 4. **总结**

std::pair 是 C++ 标准库中的一个类模板,用于将两个异构对象组合成一个单元。它在头文件 <utility> 中定义,并且是 std::tuple 的一个特例,专门用于处理两个元素的情况。 std::pair 在许多情况下非常有用,例如作为关联容器(如 std::map)的键值对,或者当需要返回多个值时。

1. 概述

std::pair 的定义如下:

template<class T1, class T2>
struct pair {// 成员类型typedef T1 first_type;typedef T2 second_type;// 成员对象T1 first;T2 second;// 构造函数constexpr pair() : first(T1()), second(T2()) {}constexpr pair(const T1& x, const T2& y) : first(x), second(y) {}constexpr pair(T1&& x, T2&& y) : first(std::move(x)), second(std::move(y)) {}template<class U1, class U2>constexpr pair(U1&& x, U2&& y) : first(std::forward<U1>(x)), second(std::forward<U2>(y)) {}// 其他构造函数...// 成员函数constexpr void swap(pair& other) noexcept(/* see below */);// ...
};

2. 成员类型和成员对象

  • first_type:第一个元素的类型,即 T1
  • second_type:第二个元素的类型,即 T2
  • first:存储第一个元素的成员变量。
  • second:存储第二个元素的成员变量。

3. 构造函数

std::pair 提供了多种构造方式:

  • 默认构造:使用默认构造函数初始化 firstsecond
  • 复制构造:从两个已有的对象构造 pair
  • 移动构造:从两个右值引用的对象构造 pair
  • 模板构造:允许从不同类型的对象构造 pair,支持隐式转换。

4. 成员函数

  • operator=:赋值操作符,用于将另一个 pair 的内容赋值给当前 pair
  • swap:交换两个 pair 的内容。自 C++11 起,swap 函数被标记为 noexcept,如果 T1T2swap 操作也是 noexcept 的话。

5. 非成员函数

5.1 make_pair

make_pair 是一个方便的函数模板,用于创建 std::pair 对象。它会根据传入的参数类型自动推导出 pair 的类型。

template<class T1, class T2>
constexpr pair<T1, T2> make_pair(T1 t, T2 u);

示例:

#include <utility>int main() {auto p = std::make_pair(42, "Hello");std::cout << p.first << ", " << p.second << '\n';
}

输出:

42, Hello
5.2 比较运算符

std::pair 支持按字典顺序进行比较。C++20 之前,提供了以下比较运算符:

  • operator==:检查两个 pair 是否相等。
  • operator!=:检查两个 pair 是否不相等。
  • operator<:按字典顺序比较两个 pair
  • operator<=:按字典顺序检查一个 pair 是否小于或等于另一个 pair
  • operator>:按字典顺序检查一个 pair 是否大于另一个 pair
  • operator>=:按字典顺序检查一个 pair 是否大于或等于另一个 pair

C++20 引入了三路比较运算符 operator<=>,它可以在支持三路比较的类型上使用。

template<class T1, class T2>
constexpr std::strong_ordering operator<=>(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs);
5.3 std::swap

std::swap 专门化用于交换两个 pair 的内容。自 C++11 起,std::swap 可以更高效地交换 pair 的元素。

template<class T1, class T2>
void swap(pair<T1, T2>& x, pair<T1, T2>& y) noexcept(/* see below */);
5.4 std::get

std::get 是 C++11 引入的一个模板函数,用于访问 pair 的元素。它可以与 std::tuple 一起使用,但在 pair 上也可以工作。

template<std::size_t I, class T1, class T2>
constexpr typename std::tuple_element<I, pair<T1, T2>>::type& get(pair<T1, T2>& p);template<std::size_t I, class T1, class T2>
constexpr typename std::tuple_element<I, pair<T1, T2>>::type&& get(pair<T1, T2>&& p);template<std::size_t I, class T1, class T2>
constexpr const typename std::tuple_element<I, pair<T1, T2>>::type& get(const pair<T1, T2>& p);

示例:

#include <utility>
#include <iostream>int main() {std::pair<int, double> p(42, 3.14);std::cout << std::get<0>(p) << ", " << std::get<1>(p) << '\n';
}

输出:

42, 3.14

6. 辅助类

6.1 std::tuple_sizestd::tuple_element

std::tuple_sizestd::tuple_element 是 C++11 引入的模板类,用于获取 pair 的大小和元素类型。

  • std::tuple_size<std::pair<T1, T2>>:表示 pair 的大小为 2。
  • std::tuple_element<0, std::pair<T1, T2>>:表示 pair 的第一个元素类型为 T1
  • std::tuple_element<1, std::pair<T1, T2>>:表示 pair 的第二个元素类型为 T2
6.2 std::common_typestd::basic_common_reference

C++23 引入了 std::common_typestd::basic_common_reference 的特化,用于确定两个 pair 的公共类型和公共引用类型。

6.3 std::formatter

C++23 引入了 std::formatter 的特化,用于支持 std::pair 的格式化输出。这使得 std::pair 可以与 std::format 等函数一起使用。

7. 析构函数

如果 T1T2 都不可能是具有非平凡析构函数的 cv 限定类类型或数组,则 pair 的析构函数是平凡的。这意味着在这种情况下,pair 的析构不会引入额外的开销。

8. 示例代码

以下是一个完整的示例,展示了 std::pair 的基本用法:

#include <iostream>
#include <utility>
#include <string>int main() {// 创建一个 pairstd::pair<int, std::string> p(42, "Hello");// 访问 pair 的元素std::cout << "First: " << p.first << ", Second: " << p.second << '\n';// 使用 make_pair 创建 pairauto p2 = std::make_pair(3.14, 'A');std::cout << "First: " << p2.first << ", Second: " << p2.second << '\n';// 比较两个 pairstd::pair<int, int> p3(1, 2);std::pair<int, int> p4(1, 3);if (p3 < p4) {std::cout << "p3 is less than p4\n";}// 交换两个 pairp3.swap(p4);std::cout << "After swap: p3 = (" << p3.first << ", " << p3.second << "), p4 = (" << p4.first << ", " << p4.second << ")\n";// 使用 std::get 访问元素std::pair<double, char> p5(3.14, 'B');std::cout << "First: " << std::get<0>(p5) << ", Second: " << std::get<1>(p5) << '\n';return 0;
}

9. 总结

std::pair 是 C++ 标准库中一个非常有用的工具,特别适用于需要将两个不同类型的数据组合在一起的情况。它提供了丰富的构造函数、成员函数和非成员函数,使得操作 pair 变得非常灵活和方便。std::pair 还与其他标准库功能(如 std::tuplestd::mapstd::set 等)无缝集成,进一步扩展了其应用场景。

如果你有更多具体的问题或需要进一步的帮助,请随时提问!

std::pair 是 C++ 标准库中一个非常灵活的工具,它可以与其他标准库功能无缝集成,从而扩展其应用场景。下面我将分别介绍 std::pair 如何与 std::tuplestd::mapstd::set 集成,并提供具体的例子。

1. std::pairstd::tuple 的集成

std::pairstd::tuple 的特例,std::tuple 可以看作是 std::pair 的泛化版本,允许存储任意数量的元素。因此,std::pair 可以很容易地转换为 std::tuple,反之亦然。

示例:将 std::pair 转换为 std::tuple
#include <iostream>
#include <utility> // for std::pair
#include <tuple>   // for std::tupleint main() {// 创建一个 std::pairstd::pair<int, double> p(42, 3.14);// 将 std::pair 转换为 std::tupleauto t = std::tuple(p.first, p.second);// 访问 tuple 中的元素std::cout << "Tuple contains: " << std::get<0>(t) << ", " << std::get<1>(t) << '\n';return 0;
}
输出:
Tuple contains: 42, 3.14
示例:将 std::tuple 转换为 std::pair
#include <iostream>
#include <utility> // for std::pair
#include <tuple>   // for std::tupleint main() {// 创建一个 std::tuplestd::tuple<int, double> t(42, 3.14);// 将 std::tuple 转换为 std::pairauto p = std::make_pair(std::get<0>(t), std::get<1>(t));// 访问 pair 中的元素std::cout << "Pair contains: " << p.first << ", " << p.second << '\n';return 0;
}
输出:
Pair contains: 42, 3.14

2. std::pairstd::map 的集成

std::map 是一个关联容器,用于存储键值对。std::pair 经常用于表示这些键值对。实际上,std::map 的插入操作返回的是一个 std::pair,其中包含插入的迭代器和一个布尔值,表示插入是否成功。

示例:使用 std::pair 插入和访问 std::map 中的元素
#include <iostream>
#include <map>
#include <utility> // for std::pairint main() {// 创建一个 std::mapstd::map<std::string, int> student_grades;// 使用 std::pair 插入元素student_grades.insert(std::make_pair("Alice", 95));student_grades.insert(std::make_pair("Bob", 88));student_grades.insert(std::make_pair("Charlie", 92));// 访问 map 中的元素for (const auto& [name, grade] : student_grades) {std::cout << name << ": " << grade << '\n';}// 插入并检查是否成功auto result = student_grades.insert(std::make_pair("Alice", 100));if (!result.second) {std::cout << "Insertion failed: Key 'Alice' already exists.\n";}return 0;
}
输出:
Alice: 95
Bob: 88
Charlie: 92
Insertion failed: Key 'Alice' already exists.
解释:
  • student_grades.insert(std::make_pair("Alice", 95)) 插入了一个键值对,其中 "Alice" 是键,95 是值。
  • auto result = student_grades.insert(std::make_pair("Alice", 100)) 返回一个 std::pair,其中第一个元素是插入的迭代器,第二个元素是一个布尔值,表示插入是否成功。由于 "Alice" 已经存在于 map 中,插入失败,result.secondfalse

3. std::pairstd::set 的集成

std::set 是一个有序集合,存储唯一的元素。虽然 std::set 通常用于存储单个类型的元素,但它也可以存储 std::pair,并且可以基于 pair 的两个元素进行排序。

示例:使用 std::pair 存储多个属性的唯一组合
#include <iostream>
#include <set>
#include <utility> // for std::pairint main() {// 创建一个 std::set,存储 std::pairstd::set<std::pair<int, std::string>> unique_pairs;// 插入一些 pairunique_pairs.insert(std::make_pair(1, "Apple"));unique_pairs.insert(std::make_pair(2, "Banana"));unique_pairs.insert(std::make_pair(3, "Cherry"));// 插入重复的 pair(不会插入)unique_pairs.insert(std::make_pair(1, "Apple"));// 遍历 set 并输出元素for (const auto& [number, fruit] : unique_pairs) {std::cout << number << ": " << fruit << '\n';}return 0;
}
输出:
1: Apple
2: Banana
3: Cherry
解释:
  • std::set 会自动根据 pair 的字典顺序进行排序。首先比较 first 元素,如果相同则比较 second 元素。
  • 由于 std::set 只存储唯一的元素,尝试插入相同的 pair(如 std::make_pair(1, "Apple"))不会改变集合的内容。
自定义排序规则

你还可以通过提供自定义的比较函数来控制 std::setstd::pair 的排序方式。例如,如果你想只根据 pairsecond 元素进行排序:

#include <iostream>
#include <set>
#include <utility> // for std::pair// 自定义比较函数,只比较 second 元素
struct CompareSecond {bool operator()(const std::pair<int, std::string>& a, const std::pair<int, std::string>& b) const {return a.second < b.second;}
};int main() {// 创建一个 std::set,使用自定义比较函数std::set<std::pair<int, std::string>, CompareSecond> unique_pairs;// 插入一些 pairunique_pairs.insert(std::make_pair(1, "Apple"));unique_pairs.insert(std::make_pair(2, "Banana"));unique_pairs.insert(std::make_pair(3, "Cherry"));// 遍历 set 并输出元素for (const auto& [number, fruit] : unique_pairs) {std::cout << number << ": " << fruit << '\n';}return 0;
}
输出:
1: Apple
2: Banana
3: Cherry
解释:
  • 在这个例子中,std::set 根据 pairsecond 元素(即字符串)进行排序,而不是默认的字典顺序。

4. 总结

  • std::pairstd::tuplestd::pairstd::tuple 的特例,两者可以轻松互转,适用于需要处理两个元素的情况。
  • std::pairstd::mapstd::map 内部使用 std::pair 来存储键值对,insert 操作返回的也是一个 std::pair,方便检查插入是否成功。
  • std::pairstd::setstd::set 可以存储 std::pair,并且可以根据 pair 的两个元素进行排序,甚至可以通过自定义比较函数来控制排序规则。

通过这些集成,std::pair 成为了 C++ 标准库中非常强大且灵活的工具,适用于多种场景。如果你有更多具体的问题或需要进一步的帮助,请随时提问!


http://www.ppmy.cn/news/1554362.html

相关文章

书生浦语第四期L1G4000——InternLM + LlamaIndex RAG 实践

1.环境、模型准备 1.1 配置基础环境 安装python依赖包 pip install einops0.7.0 protobuf5.26.1 1.2 安装Llamaindex pip install llama-index0.11.20 pip install llama-index-llms-replicate0.3.0 pip install llama-index-llms-openai-like0.2.0 pip install llama-ind…

自回归模型(AR )

最近看到一些模型使用了自回归方法&#xff0c;这里就学习一下整理一下相关内容方便以后查阅。 自回归模型&#xff08;AR &#xff09; 自回归模型&#xff08;AR &#xff09;AR 模型的引入AR 模型的定义参数的估计方法模型阶数选择平稳性与因果性条件自相关与偏自相关函数优…

Java 中的方法重写

在 Java 中&#xff0c;方法重写&#xff08;Method Overriding&#xff09;是面向对象编程的一个重要概念&#xff0c;它指的是子类中存在一个与父类中相同名称、相同参数列表和相同返回类型的方法。方法重写使得子类可以提供特定的实现&#xff0c;从而覆盖&#xff08;或改变…

等保2.0数据库测评之SQL server数据库测评

一、SQL server数据库介绍 SQL server美国Microsoft公司推出的一种关系型数据库系统。SQL Server是一个可扩展的、高性能的、为分布式客户机/服务器计算所设计的数据库管理系统。 本次安装环境为Windows10专业版操作系统&#xff0c;数据库版本为Microsoft SQL Server 2019 (…

算法学习之贪心算法

前言 记录一下&#xff0c;免得又又忘了 贪心算法 在刚接触的时候&#xff0c;我一直觉得贪心和动态规划有相似之处&#xff0c;但做过的题目看&#xff0c;贪心似乎不用迭代

基于协同过滤的图书推荐系统 爬虫分析可视化【源码+文档】

【1】系统介绍 研究背景 随着互联网的普及和电子商务的发展&#xff0c;用户可以在线获取大量的图书资源。然而&#xff0c;面对海量的信息&#xff0c;用户往往难以找到自己真正感兴趣的书籍。同时&#xff0c;对于在线书店或图书馆等提供图书服务的平台来说&#xff0c;如何…

selenium学习:等待方式

隐式等待 1.针对查找元素设置最大的超时时间 2.可以全局性的设置 3.不满足时&#xff0c;提示no such element driver.implicitly_wait(5) #对查找元素最大的超时时间&#xff0c;如果超过最大等待时间后&#xff0c;没有找到元素&#xff0c;则会报错&#xff1a;no such #e…

Android UI:ViewTree:源码分析:事件处理:显示事件

文章目录 概述测量:measure和onMeasure​​​​​​​ View.MeasureSpecViewViewGroupLinearLayoutRelativeLayout布局:layout和onLayout ViewViewGroupLinearLayoutRelativeLayout绘制:dispatchDraw、draw和onDraw ViewViewGroupLinearLayoutRelativeLayout总结概述 显示事…