有一个基于范围的for循环,其语法为:
for(auto& i : array)
它适用于常量数组,但不适用于基于指针的动态数组,如
int *array = new int[size];
for(auto& i : array)
cout<< i << endl;
它提供有关替换失败的错误和警告,例如:
错误] C:\ Users \ Siegfred \ Documents \ C-Free \ Temp \ Untitled2.cpp:16:16:错误:没有匹配函数来调用'begin(int *&amp;)'
如何在动态数组中使用这种新语法?
答案 0 :(得分:23)
要使用基于范围的for-loop ,您必须提供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
也位于名称空间{{1}中}。如果您不想篡改标准命名空间,只需创建自己的小配对类,并在命名空间中重载std
和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}; }
答案 1 :(得分:17)
您不能将range-for-loop与动态分配的数组一起使用,因为编译器无法推断出此数组的开始和结束。您应该始终使用容器而不是容器,例如std::vector
。
std::vector<int> v(size);
for(const auto& elem: v)
// do something
答案 2 :(得分:10)
您无法直接在动态分配的数组上执行基于范围的循环,因为您只拥有指向第一个元素的指针。没有关于其大小的信息,编译器可以使用它来执行循环。惯用的C ++解决方案是用std::vector
替换动态分配的数组:
std::vector<int> arr(size);
for(const auto& i : arr)
std::cout<< i << std::endl;
或者,您可以使用基于指针和偏移量提供开始和结束迭代器的范围类型。查看boost.range库中的某些类型,或GSL范围内的提案(示例实现here,参考C ++ 20建议类型here)
请注意,基于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;
但在这两种情况下,大小都需要是编译时常量。
答案 3 :(得分:1)
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;
}
不幸的是,截至撰写本文时,目前的编译器似乎还没有支持这一点。
当然,如果你有选择的话,最好从一开始就使用std::vector
而不是C风格的数组。
答案 4 :(得分:0)
不是为std::begin
的指针定义std::end
和std::pair
(顺便说一下,在undefined behaviour中在std::
中定义它们)并展开了自己的包装,例如suggested before,则可以使用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;
答案 5 :(得分:-2)
请参阅此页面http://www.codeproject.com/Articles/570638/Ten-Cplusplus11-Features-Every-Cplusplus-Developer并找到“非成员begin()和end()”一章。这可能是你想要实现的目标。