std::begin并std::end知道一个container或一个的开始和结束array.
它很容易知道end和begin的vector为例子,因为它是一个类,给出了这样的信息.但是,它如何知道如下结束array呢?
int simple_array[5]{1, 2, 3, 4, 5};
auto beg=std::begin(simple_array);
auto en=std::end(simple_array);
Run Code Online (Sandbox Code Playgroud)
std::begin并不难知道数组的起始位置.但它如何知道它的结束?将常数整数5存储在某处吗?
如果我得到一些低级信息的答案,我将不胜感激.
leg*_*s2k 26
是常数整数5会存储在哪里?
是的,它是数组类型的一部分.但不,它没有明确地存储在任何地方.当你有
int i[5] = { };
Run Code Online (Sandbox Code Playgroud)
的类型i是int[5].Shafik的回答谈到了如何使用这个长度来实现end.
如果您使用的constexpr是C++ 11,那么使用它将是一种简单的方法
template <typename T, size_t N>
inline constexpr size_t
arrLen(const T (&arr) [N]) {
return N;
}
Run Code Online (Sandbox Code Playgroud)
如果您的C++ 11之前的编译器constexpr不可用,则可能无法在编译时评估上述函数.所以在这种情况下,你可以使用这个:
template <typename T, size_t N>
char (&arrLenFn(const T (&arr) [N]))[N];
#define arrLen(arr) sizeof(arrLenFn(arr))
Run Code Online (Sandbox Code Playgroud)
首先,我们声明一个函数返回对N chars 数组的引用,即sizeof此函数现在将是数组的长度.然后我们有一个宏来包装它,以便它在调用者端可读.
注意:两个相同基本类型但长度不同的数组仍然是两种完全不同的类型.int[3]是不一样的int[2].但是,数组衰减会int*在两种情况下都能得到你.阅读如何在C++中使用数组?如果你想了解更多.
Sha*_*our 25
但是,它如何知道数组的结束
它使用模板非类型参数来推导数组的大小,然后可以使用它来生成结束指针.来自std :: end的cppreference部分的C++ 11签名如下:
template< class T, std::size_t N >
T* end( T (&array)[N] );
Run Code Online (Sandbox Code Playgroud)
正如hvd所说,由于它是通过引用传递的,因此可以防止衰减到指针.
实施类似于:
template< class T, std::size_t N >
T* end( T (&array)[N] )
{
return array + N ;
}
Run Code Online (Sandbox Code Playgroud)
是否将常数整数5存储在哪里?
5或者N是数组类型的一部分,因此N在编译时可用.例如,将sizeof应用于数组将为我们提供数组中的总字节数.
很多时候我们看到一个数组按值传递给一个函数.在这种情况下,数组衰减到指向存储在数组中的类型的指针.所以现在大小信息丢失了.通过引用传递允许我们避免这种信息丢失并N从类型中提取大小.