std::end 如何知道数组的结尾
How does std::end know the end of an array?
std::begin
和std::end
知道container
或array
的开始和结束。
例如,很容易知道vector
的end
和begin
,因为它是一个提供此信息的类。但是,它如何知道像下面这样array
的结束呢?
int simple_array[5]{1, 2, 3, 4, 5};
auto beg=std::begin(simple_array);
auto en=std::end(simple_array);
std::begin
不难知道阵列从哪里开始。但是它怎么知道它在哪里结束呢?常量整数5
会存储在某个地方吗?
如果我得到一些低级信息的答案,我将不胜感激。
但是,它怎么知道数组的结尾
它使用模板非类型参数来推断数组的大小,然后可以使用该参数生成结束指针。std::end 的 cpp首选项部分中的 C++11 签名如下所示:
template< class T, std::size_t N >
T* end( T (&array)[N] );
正如 hvd 所指出的,由于它是通过引用传递的,因此可以防止衰减到指针。
实现将类似于:
template< class T, std::size_t N >
T* end( T (&array)[N] )
{
return array + N ;
}
常量整数 5 将存储在某个地方吗?
5
或N
是数组类型的一部分,因此N
在编译时可用。例如,将 sizeof 应用于数组将给我们数组中的字节总数。
很多时候,我们看到一个数组按值传递给函数。在这种情况下,数组将衰减到指向存储在数组中的类型的指针。所以现在大小信息丢失了。通过引用传递,我们可以避免这种信息丢失,并从类型中提取大小N
。
常量整数 5 将存储在某个地方吗?
是的,它是数组类型的一部分。但是不,它没有明确存储在任何地方。当你有
int i[5] = { };
i
的类型是 int[5]
.Shafik 的回答谈到了如何使用这个长度来实现end
.
如果您已经C++11,那么使用constexpr
将是最简单的方法
template <typename T, size_t N>
inline constexpr size_t
arrLen(const T (&arr) [N]) {
return N;
}
如果你有一个 C++11 之前的编译器,其中constexpr
不可用,则在编译时可能不会计算上述函数。因此,在这种情况下,您可以使用以下内容:
template <typename T, size_t N>
char (&arrLenFn(const T (&arr) [N]))[N];
#define arrLen(arr) sizeof(arrLenFn(arr))
首先,我们声明一个函数,返回对 N char
s 数组的引用,即 sizeof
此函数现在将是数组的长度。然后我们有一个宏来包装它,以便在调用方端可读。
注意:两个基本类型相同但长度不同的数组仍然是两种完全不同的类型。 int[3]
与int[2]
不同.但是,在这两种情况下,数组衰减都会使您int*
。阅读如何在C++中使用数组?如果你想了解更多。
因为您要将数组传递给std::end
,而数组的类型为 T [N]
。 std::end
可以通过查看类型中的N
来判断数组何时结束。