定义于头文件 <array>
template< class T, |
(C++11 起) |
std::array
是封装固定大小数组的容器。
此容器是一个聚合类型,其语义等同于保有一个 C 风格数组 T[N] 作为其唯一非静态数据成员的结构体。不同于 C 风格数组,它不会自动退化成 T* 。它能作为聚合类型聚合初始化,只要有至多 N
个能转换成 T
的初始化器: std::array<int, 3> a = {1,2,3}; 。
该结构体结合了 C 风格数组的性能、可访问性与容器的优点,比如可获取大小、支持赋值、随机访问迭代器等。
std::array
满足容器 (Container) 和可逆容器 (ReversibleContainer) 的要求,除了默认构造的 array 是非空的,以及进行交换的复杂度是线性,它满足连续容器 (ContiguousContainer) (C++17 起)的要求并部分满足序列容器 (SequenceContainer) 的要求。
当其长度为零时 array
( N == 0
)有特殊情况。此时, array.begin() == array.end() ,并拥有某个唯一值。在零长 array
上调用 front() 或 back() 是未定义的。
亦可将 array
当做拥有 N
个同类型元素的元组。
迭代器非法化
按照规则,指向 array
的迭代器在 array
的生存期间决不非法化。然而要注意,在 swap 时,迭代器将继续指向同一 array
的元素,并将改变元素的值。
非成员函数
按照字典顺序比较 array 中的值
operator==,!=,<,<=,>,>=(std::array)
template< class T, std::size_t N > bool operator==( const std::array<T, N>& lhs, const std::array<T, N>& rhs ); |
(1) | (C++20 前) |
template< class T, std::size_t N > constexpr bool operator==( const std::array<T, N>& lhs, const std::array<T, N>& rhs ); |
(C++20 起) | |
template< class T, std::size_t N > bool operator!=( const std::array<T, N>& lhs, const std::array<T, N>& rhs ); |
(2) | (C++20 前) |
template< class T, std::size_t N > constexpr bool operator!=( const std::array<T, N>& lhs, const std::array<T, N>& rhs ); |
(C++20 起) | |
template< class T, std::size_t N > bool operator<( const std::array<T, N>& lhs, const std::array<T, N>& rhs ); |
(3) | (C++20 前) |
template< class T, std::size_t N > constexpr bool operator<( const std::array<T, N>& lhs, const std::array<T, N>& rhs ); |
(C++20 起) | |
template< class T, std::size_t N > bool operator<=( const std::array<T, N>& lhs, const std::array<T, N>& rhs ); |
(4) | (C++20 前) |
template< class T, std::size_t N > constexpr bool operator<=( const std::array<T, N>& lhs, const std::array<T, N>& rhs ); |
(C++20 起) | |
template< class T, std::size_t N > bool operator>( const std::array<T, N>& lhs, const std::array<T, N>& rhs ); |
(5) | (C++20 前) |
template< class T, std::size_t N > constexpr bool operator>( const std::array<T, N>& lhs, const std::array<T, N>& rhs ); |
(C++20 起) | |
template< class T, std::size_t N > bool operator>=( const std::array<T, N>& lhs, const std::array<T, N>& rhs ); |
(6) | (C++20 前) |
template< class T, std::size_t N > constexpr bool operator>=( const std::array<T, N>& lhs, const std::array<T, N>& rhs ); |
(C++20 起) |
比较二个 array
的内容。
1-2) 检查 lhs
与 rhs
的内容是否相等,即 lhs
中的每个元素是否与 rhs
中同一位置的元素比较相等。
3-6) 按字典序比较 lhs
与 rhs
的内容。由等价于 std::lexicographical_compare 的函数进行比较。
参数
lhs, rhs | - | 要比较内容的容器 |
- 为使用重载 (1-2) , T 必须满足可相等比较 (EqualityComparable) 的要求。 |
||
- 为使用重载 (3-6) , T 必须满足可小于比较 (LessThanComparable) 的要求。顺序关系必须建立全序。 |
返回值
1) 若容器内容相等则为 true ,否则为 false 。
2) 若容器的内容不相等则为 true ,否则为 false 。
3) 若 lhs
的内容按字典序小于 rhs
的内容则为 true ,否则为 false 。
4) 若 lhs
的内容按字典序小于或等于 rhs
的内容则为 true ,否则为 false 。
5) 若 lhs
的内容按字典序大于 rhs
的内容则为 true ,否则为 false 。
6) 若 lhs
的内容按字典序大于或等于 rhs
的内容则为 true ,否则为 false 。
复杂度
与容器大小成线性。
访问 array 的一个元素
std::get(std::array)
template< size_t I, class T, size_t N > |
(1) | (C++11 起) |
template< size_t I, class T, size_t N > |
(2) | (C++11 起) |
template< size_t I, class T, size_t N > |
(3) | (C++11 起) |
template< size_t I, class T, size_t N > |
(4) | (C++17 起) |
从 array 提取第 Ith
个元素。
I
必须是范围 [0, N)
中的整数值。与 at() 或 operator[] 相反,这在编译时强制。
参数
a | - | 要提取其内容的数组 |
返回值
到 a
的 Ith
元素的引用。
时间复杂度
常数。
特化 std::swap 算法
std::swap(std::array)
template< class T, std::size_t N > void swap( array<T,N>& lhs, array<T,N>& rhs ); |
(C++11 起) (C++17 前) |
|
template< class T, std::size_t N > void swap( array<T,N>& lhs, array<T,N>& rhs ) noexcept(/* see below */); |
(C++17 起) (C++20 前) |
|
template< class T, std::size_t N > constexpr void swap( array<T,N>& lhs, array<T,N>& rhs ) noexcept(/* see below */); |
(C++20 起) |
为 std::array 特化 std::swap 算法。交换 lhs
与 rhs
的内容。调用 lhs.swap(rhs) 。
此重载仅若 |
(C++17 起) |
参数
lhs, rhs | - | 要交换内容的容器 |
返回值
(无)
复杂度
与容器大小成线性。
异常
noexcept 规定: noexcept(noexcept(lhs.swap(rhs))) |
(C++17 起) |
从内建数组创建 std::array 对象
std::to_array
template<class T, std::size_t N> |
(1) | (C++20 起) |
template<class T, std::size_t N> |
(2) | (C++20 起) |
从一维内建数组 a
创建 std::array 。从 a
的对应元素复制初始化 std::array
的元素。不支持复制或移动多维内建数组。
1) 对 0, ..., N - 1
中的每个 i
,以 a[i] 复制初始化结果的对应元素。若 std::is_constructible_v<T, T&> 为 false 则此重载为病式。
2) 对 0, ..., N - 1
中的每个 i
,以 std::move(a[i]) 复制初始化结果的对应元素。若 std::is_move_constructible_v<T> 为 false 则此重载为病式。
std::is_array_v<T> 为 true 时两个重载均为病式。
参数
a | - | 要转换成 std::array 的内建数组 |
类型要求 | ||
- 为使用重载 (1) , T 必须满足可复制构造 (CopyConstructible) 的要求。 |
||
- 为使用重载 (2) , T 必须满足可移动构造 (MoveConstructible) 的要求。 |
返回值
1) std::array<std::remove_cv_t<T>, N>{ a[0], ..., a[N - 1] }
2) std::array<std::remove_cv_t<T>, N>{ std::move(a[0]), ..., std::move(a[N - 1]) }
注解
有一些不能使用 std::array 的类模板实参推导而 to_array
可用的情况:
to_array
能在手工指定std::array
的元素类型并推导长度时指定,这在想要隐式转换时会更好。to_array
能赋值字符串字面量,而类模板实参推导创建有一个指向其首字符的std::array
。
std::to_array<long>({3, 4}); // OK :隐式转换
// std::array<long>{3, 4}; // 错误:模板参数太少
std::to_array("foo"); // 创建 std::array<char, 4>{ 'f', 'o', 'o', '\0' }
std::array{"foo"}; // 创建 std::array<const char*, 1>{ +"foo" }
可能的实现
版本一 |
---|
namespace detail { template <class T, std::size_t N, std::size_t... I> constexpr std::array<std::remove_cv_t<T>, N> to_array_impl(T (&a)[N], std::index_sequence<I...>) { return { {a[I]...} }; } } template <class T, std::size_t N> constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N]) { return detail::to_array_impl(a, std::make_index_sequence<N>{}); } |
版本二 |
namespace detail { template <class T, std::size_t N, std::size_t... I> constexpr std::array<std::remove_cv_t<T>, N> to_array_impl(T (&&a)[N], std::index_sequence<I...>) { return { {std::move(a[I])...} }; } } template <class T, std::size_t N> constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&&a)[N]) { return detail::to_array_impl(std::move(a), std::make_index_sequence<N>{}); } |
辅助类
获得 array 的大小
std::tuple_size(std::array)
template< class T, size_t N > class tuple_size< array<T, N> > : |
(1) | (C++11 起) |
提供作为编译时常量表达式访问 std::array 中元素数量的方法。
继承自 std::integral_constant
成员常量
value [静态] |
N , array 中的元素数(公开静态成员常量) |
成员函数
operator std::size_t |
转换对象为 std::size_t ,返回 value (公开成员函数) |
operator() (C++14) |
返回 value (公开成员函数) |
成员类型
类型 | 定义 |
value_type |
std::size_t |
type |
std::integral_constant<std::size_t, value> |
获得 array 元素的类型
std::tuple_element<std::array>
template< std::size_t I, class T, std::size_t N > |
(C++11 起) |
使用类 tuple 接口,提供 array 元素类型的编译时带下标访问
成员类型
成员类型 | 定义 |
type | array 的元素类型 |
可能的实现
template<std::size_t I, class T> struct tuple_element; template<std::size_t I, class T, std::size_t N> struct tuple_element<I, std::array<T,N> > { using type = T; }; |
调用示例
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <functional>
#include <time.h>
#include <array>
using namespace std;
struct Cell
{
int x;
int y;
Cell() = default;
Cell(int a, int b): x(a), y(b) {}
Cell &operator +=(const Cell &cell)
{
x += cell.x;
y += cell.y;
return *this;
}
Cell &operator +(const Cell &cell)
{
x += cell.x;
y += cell.y;
return *this;
}
Cell &operator *(const Cell &cell)
{
x *= cell.x;
y *= cell.y;
return *this;
}
Cell &operator ++()
{
x += 1;
y += 1;
return *this;
}
bool operator <(const Cell &cell) const
{
if (x == cell.x)
{
return y < cell.y;
}
else
{
return x < cell.x;
}
}
bool operator >(const Cell &cell) const
{
if (x == cell.x)
{
return y > cell.y;
}
else
{
return x > cell.x;
}
}
bool operator ==(const Cell &cell) const
{
return x == cell.x && y == cell.y;
}
};
std::ostream &operator<<(std::ostream &os, const Cell &cell)
{
os << "{" << cell.x << "," << cell.y << "}";
return os;
}
template<class T>
void my_tuple_size(const string &name, T t)
{
//提供作为编译时常量表达式访问 std::array 中元素数量的方法。
int a[std::tuple_size<T>::value]; // 能用于编译时
std::cout << name << " ";
std::cout << "std::tuple_size<T>::value: " << std::tuple_size<T>::value << std::endl;
}
int main()
{
std::cout << std::boolalpha;
std::mt19937 g{std::random_device{}()};
srand((unsigned)time(NULL));
auto generate = []()
{
int n = std::rand() % 10 + 110;
Cell cell{n, n};
return cell;
};
//遵循聚合初始化的规则初始化 array (注意默认初始化可以导致非类的 T 的不确定值)
std::array<Cell, 6> array1;
std::generate(array1.begin(), array1.end(), generate);
std::cout << "array1: ";
std::copy(array1.begin(), array1.end(), std::ostream_iterator<Cell>(std::cout, " "));
std::cout << std::endl;
std::array<Cell, 6> array2;
std::generate(array2.begin(), array2.end(), generate);
std::cout << "array2: ";
std::copy(array2.begin(), array2.end(), std::ostream_iterator<Cell>(std::cout, " "));
std::cout << std::endl;
std::array<Cell, 6> array3 = array1;
std::cout << "array3: ";
std::copy(array3.begin(), array3.end(), std::ostream_iterator<Cell>(std::cout, " "));
std::cout << std::endl;
std::cout << std::endl;
//比较二个 array 的内容。
//1-2) 检查 lhs 与 rhs 的内容是否相等,即 lhs 中的每个元素是否与 rhs 中同一位置的元素比较相等。
//1) 若容器内容相等则为 true ,否则为 false 。
std::cout << "array1 == array2 : " << (array1 == array2) << std::endl;
std::cout << "array1 == array3 : " << (array1 == array3) << std::endl;
//2) 若容器的内容不相等则为 true ,否则为 false 。
std::cout << "array1 != array2 : " << (array1 != array2) << std::endl;
std::cout << "array1 != array3 : " << (array1 != array3) << std::endl;
//3) 若 lhs 的内容按字典序小于 rhs 的内容则为 true ,否则为 false 。
std::cout << "array1 < array2 : " << (array1 < array2) << std::endl;
std::cout << "array1 < array3 : " << (array1 < array3) << std::endl;
//4) 若 lhs 的内容按字典序小于或等于 rhs 的内容则为 true ,否则为 false 。
std::cout << "array1 <= array2 : " << (array1 <= array2) << std::endl;
std::cout << "array1 <= array3 : " << (array1 <= array3) << std::endl;
//5) 若 lhs 的内容按字典序大于 rhs 的内容则为 true ,否则为 false 。
std::cout << "array1 > array2 : " << (array1 > array2) << std::endl;
std::cout << "array1 > array3 : " << (array1 > array3) << std::endl;
//6) 若 lhs 的内容按字典序大于或等于 rhs 的内容则为 true ,否则为 false 。
std::cout << "array1 >= array2 : " << (array1 >= array2) << std::endl;
std::cout << "array1 >= array3 : " << (array1 >= array3) << std::endl;
std::cout << std::endl;
//从 array 提取第 Ith 个元素。
//I 必须是范围 [0, N) 中的整数值。与 at() 或 operator[] 相反,这在编译时强制。
std::cout << "std::get<0>(array1) : " << std::get<0>(array1) << std::endl;
std::cout << "std::get<1>(array1) : " << std::get<1>(array1) << std::endl;
std::cout << "std::get<2>(array1) : " << std::get<2>(array1) << std::endl;
std::cout << "std::get<3>(array1) : " << std::get<3>(array1) << std::endl;
std::cout << "std::get<4>(array1) : " << std::get<4>(array1) << std::endl;
std::cout << "std::get<5>(array1) : " << std::get<5>(array1) << std::endl;
std::cout << std::endl;
std::cout << "swap before:" << std::endl;
std::cout << "array1: ";
std::copy(array1.begin(), array1.end(), std::ostream_iterator<Cell>(std::cout, " "));
std::cout << std::endl;
std::cout << "array3: ";
std::copy(array3.begin(), array3.end(), std::ostream_iterator<Cell>(std::cout, " "));
std::cout << std::endl;
//为 std::array 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。
std::swap(array1, array3);
std::cout << "swap after:" << std::endl;
std::cout << "array1: ";
std::copy(array1.begin(), array1.end(), std::ostream_iterator<Cell>(std::cout, " "));
std::cout << std::endl;
std::cout << "array3: ";
std::copy(array3.begin(), array3.end(), std::ostream_iterator<Cell>(std::cout, " "));
std::cout << std::endl;
std::cout << std::endl;
my_tuple_size("array1", array1);
my_tuple_size("array1", array3);
return 0;
}