动态数组上基于范围的for循环?

时间:2022-07-14 14:28:45

There is a range-based for loop with the syntax:

有一个基于范围的for循环,语法如下:

for(auto& i : array)

It works with constant arrays but not with pointer based dynamic ones, like

它使用常量数组,但不使用基于指针的动态数组

int *array = new int[size];
for(auto& i : array)
   cout<< i << endl;

It gives errors and warnings about failure of substitution, for instance:

它给出了替换失败的错误和警告,例如:

Error] C:\Users\Siegfred\Documents\C-Free\Temp\Untitled2.cpp:16:16: error: no matching function for call to 'begin(int*&)'

错误]C:\Users\Siegfred\Documents\C-Free\Temp\Untitled2.cpp:16:16:错误:调用“begin(int*&)”没有匹配函数

How do I use this new syntax with dynamic arrays?

如何在动态数组中使用这种新语法?

5 个解决方案

#1


21  

To make use of the range-based for-loop you have to provide either begin() and end() member functions or overload the non-member begin() and end() functions. In the latter case, you can wrap your range in a std::pair and overload begin() and end() for those:

要使用基于范围的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; }
    }

Now you can use the for-loop like this:

现在你可以像这样使用for循环:

    for (auto&& i : std::make_pair(array, array + size))
        cout << i << endl;

Note, that the non-member begin() and end() functions have to be overloaded in the std namespace here, because pair also resides in namespace std. If you don't feel like tampering with the standard namespace, you can simply create your own tiny pair class and overload begin() and end() in your namespace.

注意,非会员开始()和结束()函数重载在std名称空间,因为两人还居住在名称空间性病。如果你不想篡改标准的命名空间,您可以简单地创建自己的微小的两类和过载开始()和结束()在你的名称空间。

Or, create a thin wrapper around your dynamically allocated array and provide begin() and end() member functions:

或者,围绕动态分配的数组创建一个瘦包装器,并提供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}; }

And your call site looks like this:

你的电话网站是这样的:

    for (auto&& i : wrap_array(array, size))
         std::cout << i << std::endl;

Example

例子

#2


16  

You can't use range-for-loop with dynamically allocated arrays, since compiler can't deduce begin and end of this array. You should always use containers instead of it, for example std::vector.

对于动态分配的数组,不能使用range-for-loop,因为编译器不能推断这个数组的开始和结束。您应该始终使用容器而不是容器,例如std::vector。

std::vector<int> v(size);
for(const auto& elem: v)
    // do something

#3


9  

You can't perform a range based loop over a dynamically allocated array because all you have is a pointer to the first element. There is no information concerning its size that the compiler can use to perform the loop. The idiomatic C++ solution would be to replace the dynamically allocated array by an std::vector:

不能对动态分配的数组执行基于范围的循环,因为您所拥有的只是指向第一个元素的指针。没有关于它的大小的信息,编译器可以用来执行循环。惯用的c++解决方案是将动态分配的数组替换为std::vector:

std::vector<int> arr(size);
for(const auto& i : arr)
  std::cout<< i << std::endl;

A range based for loop does work for std::array objects. You have to look over the array instance (arr), not the type (array):

基于循环的范围对std::数组对象有效。您必须查看数组实例(arr),而不是类型(数组):

std::array<int,10> arr;
for(const auto& i : arr)
  std::cout<< i << std::endl;

#4


0  

C++20 will (presumably) add std::span, which allows looping like this:

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;
}

Unfortunately, this does not yet appear to be supported by current compilers as of the time of writing.

不幸的是,在编写本文时,当前编译器似乎还不支持这一点。

Of course, if you have the choice, it is preferable to use std::vector over C-style arrays from the get-go.

当然,如果您有选择,最好从一开始就使用std::vector数组,而不是c样式数组。

#5


-2  

See this page http://www.codeproject.com/Articles/570638/Ten-Cplusplus11-Features-Every-Cplusplus-Developer and find the chapter "non-member begin() and end()". This could be what you want to achieve.

请参见这个页面http://www.codeproject.com/articles/570638 / ten - cplusplusplus11 - features-every-cplusplus - developer,找到“非成员的begin()和end()”一章。这可能是你想要实现的。

#1


21  

To make use of the range-based for-loop you have to provide either begin() and end() member functions or overload the non-member begin() and end() functions. In the latter case, you can wrap your range in a std::pair and overload begin() and end() for those:

要使用基于范围的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; }
    }

Now you can use the for-loop like this:

现在你可以像这样使用for循环:

    for (auto&& i : std::make_pair(array, array + size))
        cout << i << endl;

Note, that the non-member begin() and end() functions have to be overloaded in the std namespace here, because pair also resides in namespace std. If you don't feel like tampering with the standard namespace, you can simply create your own tiny pair class and overload begin() and end() in your namespace.

注意,非会员开始()和结束()函数重载在std名称空间,因为两人还居住在名称空间性病。如果你不想篡改标准的命名空间,您可以简单地创建自己的微小的两类和过载开始()和结束()在你的名称空间。

Or, create a thin wrapper around your dynamically allocated array and provide begin() and end() member functions:

或者,围绕动态分配的数组创建一个瘦包装器,并提供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}; }

And your call site looks like this:

你的电话网站是这样的:

    for (auto&& i : wrap_array(array, size))
         std::cout << i << std::endl;

Example

例子

#2


16  

You can't use range-for-loop with dynamically allocated arrays, since compiler can't deduce begin and end of this array. You should always use containers instead of it, for example std::vector.

对于动态分配的数组,不能使用range-for-loop,因为编译器不能推断这个数组的开始和结束。您应该始终使用容器而不是容器,例如std::vector。

std::vector<int> v(size);
for(const auto& elem: v)
    // do something

#3


9  

You can't perform a range based loop over a dynamically allocated array because all you have is a pointer to the first element. There is no information concerning its size that the compiler can use to perform the loop. The idiomatic C++ solution would be to replace the dynamically allocated array by an std::vector:

不能对动态分配的数组执行基于范围的循环,因为您所拥有的只是指向第一个元素的指针。没有关于它的大小的信息,编译器可以用来执行循环。惯用的c++解决方案是将动态分配的数组替换为std::vector:

std::vector<int> arr(size);
for(const auto& i : arr)
  std::cout<< i << std::endl;

A range based for loop does work for std::array objects. You have to look over the array instance (arr), not the type (array):

基于循环的范围对std::数组对象有效。您必须查看数组实例(arr),而不是类型(数组):

std::array<int,10> arr;
for(const auto& i : arr)
  std::cout<< i << std::endl;

#4


0  

C++20 will (presumably) add std::span, which allows looping like this:

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;
}

Unfortunately, this does not yet appear to be supported by current compilers as of the time of writing.

不幸的是,在编写本文时,当前编译器似乎还不支持这一点。

Of course, if you have the choice, it is preferable to use std::vector over C-style arrays from the get-go.

当然,如果您有选择,最好从一开始就使用std::vector数组,而不是c样式数组。

#5


-2  

See this page http://www.codeproject.com/Articles/570638/Ten-Cplusplus11-Features-Every-Cplusplus-Developer and find the chapter "non-member begin() and end()". This could be what you want to achieve.

请参见这个页面http://www.codeproject.com/articles/570638 / ten - cplusplusplus11 - features-every-cplusplus - developer,找到“非成员的begin()和end()”一章。这可能是你想要实现的。