std::array
对象可以像任何其他对象一样传递给函数。若按值传递,将产生一次昂贵的拷贝,因此我们通常通过(const)引用传参以避免拷贝。
显式指定元素类型与长度
std::array
的元素类型与长度都是其类型信息的一部分,故作为函数形参时必须同时显式给出:
#include <array>
#include <iostream>
void passByRef(const std::array<int, 5>& arr) // 必须写出 <int, 5>
{
std::cout << arr[0] << '\n';
}
int main()
{
std::array arr{ 9, 7, 5, 3, 1 }; // CTAD 推导出 std::array<int, 5>
passByRef(arr);
return 0;
}
CTAD 尚不能用于函数参数,因此不能写成 std::array
而让编译器推断模板实参。
函数模板:接受任意元素类型或长度的 std::array
若希望函数能处理任意元素类型或任意长度的 std::array
,可编写函数模板,把元素类型与长度都参数化:
#include <array>
#include <iostream>
template <typename T, std::size_t N> // 与 std::array 的模板参数声明一致
void passByRef(const std::array<T, N>& arr)
{
static_assert(N != 0); // 拒绝零长度数组
std::cout << arr[0] << '\n';
}
int main()
{
std::array arr{ 9, 7, 5, 3, 1 }; // std::array<int, 5>
passByRef(arr); // 实例化 passByRef<int, 5>
std::array arr2{ 1, 2, 3, 4, 5, 6 }; // std::array<int, 6>
passByRef(arr2); // 实例化 passByRef<int, 6>
std::array arr3{ 1.2, 3.4, 5.6, 7.8, 9.9 }; // std::array<double, 5>
passByRef(arr3); // 实例化 passByRef<double, 5>
}
警告
非类型模板参数 N
必须声明为 std::size_t
,而非 int
;否则模板无法匹配 std::array<T, std::size_t>
。
仅参数化长度(固定元素类型)
也可只把长度模板化,元素类型显式给出:
template <std::size_t N>
void passByRef(const std::array<int, N>& arr) // 元素类型固定为 int
{
static_assert(N != 0);
std::cout << arr[0] << '\n';
}
此时 double
数组将无法匹配,编译报错。
C++20 auto
非类型模板参数
C++20 起可使用 auto
让编译器自动推导非类型模板参数类型:
template <typename T, auto N>
void passByRef(const std::array<T, N>& arr) { /* ... */ }
若编译器支持,可简化模板声明。
在模板长度上静态断言
示例函数:
template <typename T, std::size_t N>
void printElement3(const std::array<T, N>& arr)
{
std::cout << arr[3] << '\n';
}
若传入 std::array<int, 2>
,运行期将越界。
可改用:
std::get<3>(arr)
编译期检查,越界时报错。static_assert(N > 3)
在函数体内断言长度,编译期阻止越界调用。
返回 std::array
与 std::vector
不同,std::array
不可移动,按值返回会复制整个数组。两种惯例做法:
按值返回
当数组不大、元素复制代价低、非性能关键时可直接返回:template <typename T, std::size_t N> std::array<T, N> inputArray() { std::array<T, N> arr{}; // 读入 N 个值 return arr; // 复制返回 }
优点:直观、可一次初始化。
缺点:有拷贝成本,需显式提供模板实参。输出参数(out-parameter)
若拷贝代价高,用非 const 引用参数:template <typename T, std::size_t N> void inputArray(std::array<T, N>& arr) { // 填充 arr }
无拷贝,但调用语法不直观,无法用于初始化。
改用
std::vector
若需动态长度或可移动,返回std::vector
即可避免拷贝。
小测验
问题 1
补全程序,使其输出:
The array (1, 4, 9, 16) has length 4
The array (h, e, l, l, o) has length 5