pair
在 C++ 标准库中,std::pair
是一个模板类,用于存储一对值。这两个值可以是不同类型的。std::pair
常用于需要将两个值组合在一起并一起传递或返回的场景。std::pair
定义在 <utility>
头文件中。
std::pair
的基本使用
1. 定义和初始化
可以通过多种方式来定义和初始化 std::pair
对象。
2. 访问元素
std::pair
有两个公开的成员变量:first
和 second
,分别用于存储一对值。
3. 比较操作
std::pair
支持比较操作,比较是按字典序进行的,即首先比较 first
元素,如果相等则比较 second
元素。
4. 修改元素
可以直接修改 first
和 second
成员变量。
使用场景
1. 函数返回多值
std::pair
常用于函数需要返回多个值的场景。
2. 结合容器使用
std::pair
常与 STL 容器一起使用,例如在 std::map
中。
tuple
在 C++11 及其后续版本中,std::tuple
是一个模板类,用于存储固定大小的不同类型的值。它可以看作是扩展版的 std::pair
,可以存储任意数量和任意类型的值。std::tuple
定义在 <tuple>
头文件中。
1. 定义和初始化 std::tuple
可以通过多种方式来定义和初始化 std::tuple
对象。
2. 访问 std::tuple
元素
可以使用 std::get
函数按索引访问 std::tuple
的元素。索引从 0 开始。
3. 修改 std::tuple
元素
可以使用 std::get
函数按索引修改 std::tuple
的元素。
4. 使用 std::tie
解构 std::tuple
std::tie
可以将 std::tuple
的元素解构到多个变量中。
5. 忽略 std::tuple
的某些元素
在解构 std::tuple
时,可以使用 std::ignore
忽略某些元素。
6. 获取 std::tuple
的大小
可以使用 std::tuple_size
获取 std::tuple
的大小。
7. 拼接 std::tuple
可以使用 std::tuple_cat
函数拼接两个或多个 std::tuple
。
使用场景
1. 函数返回多个值
std::tuple
常用于函数需要返回多个值的场景。
2. 结合容器使用
std::tuple
常与 STL 容器一起使用,例如在 std::map
中。
optional
在 C++17 中,std::optional
是一种有用的工具,用于表示一个值可能存在也可能不存在的情况。它在 <optional>
头文件中定义,通过这种方式可以避免使用裸指针或其他不安全的方式来表示可选值。
定义和初始化 std::optional
1. 包含头文件
要使用 std::optional
,首先需要包含 <optional>
头文件。
2. 定义和初始化 std::optional
可以通过多种方式来定义和初始化 std::optional
对象。
访问和修改 std::optional
的值
1. 访问值
has_value()
:检查 std::optional
是否包含值。
value()
:访问 std::optional
的值,如果 std::optional
不包含值,则抛出 std::bad_optional_access
异常。
value_or(default_value)
:如果 std::optional
包含值,则返回该值,否则返回 default_value
。
2. 修改值
reset()
:将 std::optional
重置为空。
- 赋值运算符:可以直接给
std::optional
赋值。
作为函数返回值
std::optional
常用于函数返回值,以表示一个函数可能返回一个有效值,也可能不返回值。
使用 std::optional
避免裸指针
在某些情况下,std::optional
可以替代裸指针,用于表示一个值可能不存在的情况,从而提高代码的安全性和可读性。
any
C++17 引入了 std::any
,这是一个类型安全的容器,用于存储任意类型的值。它提供了一种机制,可以在运行时存储和检索不同类型的值,而无需知道这些值的具体类型。std::any
在 <any>
头文件中定义。
std::any
的基本使用
1. 包含头文件
要使用 std::any
,首先需要包含 <any>
头文件。
2. 定义和初始化 std::any
可以通过多种方式来定义和初始化 std::any
对象。
访问 std::any
的值
可以使用 std::any_cast
来访问 std::any
存储的值。如果类型不匹配,std::any_cast
会抛出 std::bad_any_cast
异常。
1. 安全地访问值
2. 检查类型并访问值
可以使用 has_value()
检查 std::any
是否包含值,使用 type()
获取存储值的类型信息。
修改 std::any
的值
可以直接给 std::any
赋新值来修改它所存储的内容。
清空 std::any
可以使用 reset()
方法来清空 std::any
对象,使其不再包含任何值。
使用 std::any
存储用户定义的类型
std::any
可以存储用户定义的类型,但需要注意对象的生命周期和内存管理。
variant
C++17 引入了 std::variant
,这是一种类型安全的联合体(union),可以存储多种类型中的一种。与 std::any
不同,std::variant
的类型集合是固定的,并且可以在编译时知道具体存储了哪种类型。std::variant
提供了一种更安全和更高效的方式来处理多种可能类型的值。
定义和初始化 std::variant
1. 包含头文件
要使用 std::variant
,首先需要包含 <variant>
头文件。
2. 定义和初始化 std::variant
可以通过多种方式来定义和初始化 std::variant
对象。
访问和修改 std::variant
的值
1. 使用 std::get
访问值
可以使用 std::get
函数按类型或索引访问 std::variant
的值。如果类型不匹配,std::get
会抛出 std::bad_variant_access
异常。
2. 使用 std::holds_alternative
检查类型
可以使用 std::holds_alternative
检查 std::variant
当前是否持有某种类型的值。
3. 使用 std::visit
访问值
std::visit
提供了一种更灵活的方式来访问 std::variant
的值,可以通过一个访问者函数对象来处理不同类型的值。
修改 std::variant
的值
可以直接给 std::variant
赋新值来修改它所存储的内容。
获取 std::variant
的当前类型索引
可以使用 index
成员函数获取 std::variant
当前持有值的类型索引。
使用 std::monostate
std::monostate
是一种特殊类型,可以用作 std::variant
的第一个类型,以表示一种默认的无效状态。
type_traits
C++ 标准库中的 <type_traits>
头文件提供了一组模板类和模板变量,用于在编译时检查和操作类型信息。这些工具被称为“类型特征”,广泛用于元编程、模板编程和类型安全编程。
常用的类型特征
以下是一些常用的类型特征模板:
1. 基础类型特征
std::is_integral<T>
:如果 T
是整型,则为 true
。
std::is_floating_point<T>
:如果 T
是浮点型,则为 true
。
std::is_arithmetic<T>
:如果 T
是算术类型(整型或浮点型),则为 true
。
std::is_void<T>
:如果 T
是 void
,则为 true
。
示例
2. 复合类型特征
std::is_pointer<T>
:如果 T
是指针类型,则为 true
。
std::is_reference<T>
:如果 T
是引用类型,则为 true
。
std::is_array<T>
:如果 T
是数组类型,则为 true
。
std::is_function<T>
:如果 T
是函数类型,则为 true
。
std::is_enum<T>
:如果 T
是枚举类型,则为 true
。
示例
3. 资格修饰符特征
std::is_const<T>
:如果 T
是 const
限定的,则为 true
。
std::is_volatile<T>
:如果 T
是 volatile
限定的,则为 true
。
std::is_trivially_copyable<T>
:如果 T
是平凡可复制的,则为 true
。
示例
4. 类型关系特征
std::is_same<T, U>
:如果 T
和 U
是相同类型,则为 true
。
std::is_base_of<Base, Derived>
:如果 Base
是 Derived
的基类,则为 true
。
std::is_convertible<From, To>
:如果 From
类型的值可以隐式转换为 To
类型,则为 true
。
示例
5. 类型变换特征
std::remove_const<T>
:去掉 const
限定符。
std::remove_volatile<T>
:去掉 volatile
限定符。
std::remove_reference<T>
:去掉引用限定符。
std::add_const<T>
:添加 const
限定符。
std::add_pointer<T>
:将类型 T
变为指针类型 T*
。
示例
6. 辅助类型别名
C++14 引入了辅助类型别名,简化了类型特征的使用。例如,std::is_same_v<T, U>
是 std::is_same<T, U>::value
的简写形式。
示例
类型特征的高级应用
类型特征在模板编程中非常有用,可以用于启用或禁用模板的特定实例化。一个常见的用法是通过 std::enable_if
实现 SFINAE(Substitution Failure Is Not An Error)。
示例:使用 std::enable_if
functional
C++ 标准库中的 <functional>
头文件提供了一组函数对象和辅助工具,用于支持函数式编程。这些工具包括标准函数对象、std::function
类模板、绑定器(std::bind
)、函数包装器(std::ref
)、以及用于调用成员函数和成员变量的工具。
1. std::function
std::function
是一个通用的、多态的函数包装器,它可以存储、复制和调用任何可调用目标(如函数、lambda 表达式、绑定器、函数对象和其他 std::function
对象)。
示例:使用 std::function
2. std::bind
std::bind
用于创建函数对象,该对象将某些参数绑定到特定值。它返回一个新的函数对象,可以使用 std::function
进行存储。
示例:使用 std::bind
3. 标准函数对象
<functional>
提供了一些标准函数对象(如 std::plus
、std::minus
、std::multiplies
等),用于基本的算术运算和比较运算。
示例:使用标准函数对象
4. std::ref
和 std::cref
std::ref
和 std::cref
用于创建对象的引用包装器,可以将引用传递给函数对象。
示例:使用 std::ref
和 std::cref
5. 调用成员函数和访问成员变量
<functional>
提供了 std::mem_fn
、std::invoke
和 std::invoke_result
等工具,用于调用成员函数和访问成员变量。
示例:调用成员函数和访问成员变量
6. std::invoke
std::invoke
可以用于调用可调用对象(如函数指针、成员函数指针、函数对象、lambda 表达式等)。
示例:使用 std::invoke