动态数组上基于范围的for循环
Range-based for loop on a dynamic array?
有一个基于范围的for循环,语法为:
for(auto& i : array)
可用于常量数组,但不能用于基于指针的动态数组,如
int *array = new int[size];
for(auto& i : array)
cout<< i << endl;
给出替换失败的错误和警告,例如:
错误]C:UsersSiegfredDocumentsC-FreeTemp untitlet2 .cpp:16:16:错误:调用'begin(int*&)'没有匹配的函数
如何在动态数组中使用这种新语法?
要使用基于范围的for循环,您必须提供begin()
和end()
成员函数或重载非成员begin()
和end()
函数。在后一种情况下,您可以将范围包装在std::pair
中,并为那些重载begin()
和end()
:
namespace std {
template <typename T> T* begin(std::pair<T*, T*> const& p)
{ return p.first; }
template <typename T> T* end(std::pair<T*, T*> const& p)
{ return p.second; }
}
现在你可以像这样使用for循环:
for (auto&& i : std::make_pair(array, array + size))
cout << i << endl;
注意,非成员begin()
和end()
函数必须在这里的std
命名空间中重载,因为pair
也驻留在命名空间std
中。如果您不想篡改标准名称空间,您可以简单地创建自己的小pair类,并在名称空间中重载begin()
和end()
。
或者,在动态分配的数组周围创建一个薄包装器,并提供begin()
和end()
成员函数:
template <typename T>
struct wrapped_array {
wrapped_array(T* first, T* last) : begin_ {first}, end_ {last} {}
wrapped_array(T* first, std::ptrdiff_t size)
: wrapped_array {first, first + size} {}
T* begin() const noexcept { return begin_; }
T* end() const noexcept { return end_; }
T* begin_;
T* end_;
};
template <typename T>
wrapped_array<T> wrap_array(T* first, std::ptrdiff_t size) noexcept
{ return {first, size}; }
您的呼叫站点看起来像这样:
for (auto&& i : wrap_array(array, size))
std::cout << i << std::endl;
示例不能对动态分配的数组使用range-for-loop,因为编译器不能推断该数组的开始和结束。您应该始终使用容器而不是它,例如std::vector
。
std::vector<int> v(size);
for(const auto& elem: v)
// do something
你不能在动态分配的数组上直接执行基于范围的循环,因为你只有一个指向第一个元素的指针。没有关于它的大小的信息,编译器可以使用它来执行循环。惯用的c++解决方案是将动态分配的数组替换为std::vector
:
std::vector<int> arr(size);
for(const auto& i : arr)
std::cout<< i << std::endl;
也可以使用range类型,该类型提供基于指针和偏移量的开始和结束迭代器。看看助推中的一些类型。range库,或GSL span建议(此处为示例实现,此处为c++ 20建议类型的参考)。
请注意,基于范围的for循环适用于固定大小的普通数组的std::array
对象:
std::array<int,10> arr;
for(const auto& i : arr)
std::cout<< i << std::endl;
int arr[10] = .... ;
for(const auto& i : arr)
std::cout<< i << std::endl;
,但在这两种情况下,大小都需要是编译时常量
c++ 20增加了std::span
,允许这样的循环:
#include <iostream>
#include <span>
int main () {
auto p = new int[5];
for (auto &v : std::span(p, 5)) {
v = 1;
}
for (auto v : std::span(p, 5)) {
std::cout << v << 'n';
}
delete[] p;
}
当前编译器支持,例如gcc 10.1和clang 7.0.0及更高版本。(生活)
当然,如果可以选择,最好从一开始就使用std::vector
而不是c风格的数组。
代替为指针的std::pair
定义std::begin
和std::end
(顺便说一下,在std::
中定义它们是未定义的行为)并推出您自己的包装器,如前所述,您可以使用boost::make_iterator_range
:
size_t size = 16;
int *dynamic_array = new int[size];
for (const auto& i : boost::make_iterator_range(dynamic_array, dynamic_array + size))
std::cout << i << std::endl;
生活例子。
在c++ 20视图中,我们也可以使用子范围(std::ranges::subrange
)
auto p = new int[5];
//INPUT DATA TO TEST
int i = 0;
for (auto& v : std::ranges::subrange(p, p + 5)) {
v = ++i;
}
//USE SUBRANGE
for (auto v : std::ranges::subrange(p, p + 5))
std::cout << v << 'n';
- 在基于范围的for循环中使用结构化绑定声明
- 为什么 const std::p air<K,V>& 在 std::map 上基于范围的 for 循环不起作用?
- 基于范围的 for 循环:迭代使用一个元素扩展的向量
- 基于范围的 for 循环unordered_map和引用
- C++基于范围的 for 循环和元素副本
- 实现基于链表的堆栈的基于范围的 for 循环
- 在基于范围的 for 循环期间插入 std::list 的后面
- 基于范围的 for 循环range_declaration中各种说明符之间的性能差异
- 避免在基于反向范围的for循环实现中悬挂参考
- C++ - 使用基于范围的 for 循环将字符值分配给向量中的字符串不会分配值
- 转到基于范围的 for 循环中的下一个迭代器
- 使用基于数组和范围的 For 循环替换一些基本代码行
- C++:返回一个基于范围 for 循环迭代器,其中包含继承对象
- 布尔值向量的基于范围 for 循环
- 在 c++ 中基于范围的 for 循环中使用引用作为控制变量
- C++11 基于范围的 for 循环,用于 std::list
- 堆分配数组的基于范围的 for 循环
- 关于在向量向量上使用基于范围的 for 循环
- 如何使用基于范围的for循环迭代Rapidjson文档(它本身就是一个JSON数组)
- 使用基于范围的for循环取消对矢量指针的引用