您现在的位置是:首页 >技术杂谈 >c++标准模板(STL)(std::array)(五)网站首页技术杂谈

c++标准模板(STL)(std::array)(五)

繁星璀璨G 2023-05-01 22:30:02
简介c++标准模板(STL)(std::array)(五)
定义于头文件 <array>
template<

    class T,
    std::size_t N

> struct array;
(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) 的要求。

当其长度为零时 arrayN == 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) 检查 lhsrhs 的内容是否相等,即 lhs 中的每个元素是否与 rhs 中同一位置的元素比较相等。

3-6) 按字典序比较 lhsrhs 的内容。由等价于 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 >
constexpr T& get( array<T,N>& a ) noexcept;

(1)(C++11 起)

template< size_t I, class T, size_t N >
constexpr T&& get( array<T,N>&& a ) noexcept;

(2)(C++11 起)

template< size_t I, class T, size_t N >
constexpr const T& get( const array<T,N>& a ) noexcept;

(3)(C++11 起)

template< size_t I, class T, size_t N >
constexpr const T&& get( const array<T,N>&& a ) noexcept;

(4)(C++17 起)

从 array 提取第 Ith 个元素。

I 必须是范围 [0, N) 中的整数值。与 at() 或 operator[] 相反,这在编译时强制。

参数

a-要提取其内容的数组

返回值

aIth 元素的引用。

时间复杂度

常数。

 

特化 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 算法。交换 lhsrhs 的内容。调用 lhs.swap(rhs) 。

此重载仅若 N == 0 或 std::is_swappable<T>::value 为 true 才参与重载决议。

(C++17 起)

参数

lhs, rhs-要交换内容的容器

返回值

(无)

复杂度

与容器大小成线性。

异常

noexcept 规定:  

noexcept(noexcept(lhs.swap(rhs)))

(C++17 起)

 

从内建数组创建 std::array 对象

std::to_array

template<class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N]);

(1)(C++20 起)

template<class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&&a)[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', '' }
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> > :
    public integral_constant<size_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_typestd::size_t
typestd::integral_constant<std::size_t, value>

 

获得 array 元素的类型

std::tuple_element<std::array>

template< std::size_t I, class T, std::size_t N >
struct tuple_element<I, array<T, N> >;

(C++11 起)

使用类 tuple 接口,提供 array 元素类型的编译时带下标访问

成员类型

成员类型定义
typearray 的元素类型

可能的实现

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;
}

输出

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。